Rails: flash message shows in the url as param - ruby-on-rails

Hi all my flash messages work in the normal fashion but there is an action in one of my controllers where the flash message does not work.
This is the view:
<%= form_tag update_status_order_path(update_status), method: :put do |f| %>
<%= select(:order, :status, [['Active', 1], ['Inactive', 0]]) %>
<%= submit_tag "Update" %>
<% end %>
This is the controller action
def update_status
if #order.update_order_status! params[:order][:status]
redirect_to show_orders_ofert_path #order.ofert, success: "Updated!."
else
redirect_to show_orders_ofert_path #order.ofert, error: "Error."
end
end
When I send the form the action is performed correctly, but the flash message is not displayed in the layout, instead is displayed in the url as a param, just after click the Update button it reloads and shows the url like this:
http://localhost:3000/oferts/48/show_orders?success=Updated!
I have tried changing put to patch but it did not worked, even changing the action to work with respons_to block but it did not work, any idea?
this problem is only happening with that specific action because with the other actions I have the flash messages are isplayed normally.
Thanks

The success and error keys are being used as parameters to the show_orders_ofert_path because there are no parenthesis. Add parenthesis around the path helper arguments:
redirect_to show_orders_ofert_path(#order.ofert), success: "Updated!."

Related

Errors not displaying when rendering edit in Rails 7

My app is running Rails Rails 7.0.2.3
In my update controller action I have the line:
return render(:edit) unless #user_form.save
This renders the edit view on error .... but errors are not displayed.
In my edit view I am defining the form with:
form_for #user_form, url: user_path(#user_form), method: :patch do |f|
The form submits via turbo. I can see the error being added to #user_form.errors in the controller, but the instance of #user_form in the view is not changing on each form submission. If I output #user_form.inspect to the view - the id remains the same on each submission.
I have tried adding remote: false to the form_for call, but this does not seem to have an effect.
The only solution I have found is to add data: { turbo: false } to the form_for call.
Is there a better way of handling this?
you'll want to use a partial to show the errors.
you'll need to add an update.turbo_stream.erb file to this view's directory. In that file have something like:
<%= turbo_stream.update 'id_of_div_where_you_want_to_show_errors' do %>
<%= render partial: 'partial_that_displays_errors' %>
<% end %>
or your controllers update action you'll want to have something like
respond_to do |format|
format.turbo_stream { turbo_stream.update 'id_of_div_where_you_want_to_show_errors', render partial: 'partial_that_displays_errors' %>
end
Treat all this more like pseudocode and apply it to your own app, it's hard to say what's going on without seeing your code.

No route matches [POST] "/" when posting a form

I'm trying to set up a form on my index page that will pass a param myform, to the same index page via a GET request. I thought this would be relatively simple. but I'm getting an error.
I generated a controller, RecipesController, with a method called index:
class RecipesController < ApplicationController
def index
#search = params[:myform]
return #search
end
end
In this method I'm trying to get back what the user types into a textbox when a button is pressed and the GET request is fired.
Here is my view:
<h1>Recipe Finder</h1>
<%= form_tag(controller:"recipes",method:"get") do %>
<%= label_tag(:myform, "Search") %>
<%= text_field_tag(:myform) %>
<%= submit_tag("search") %>
<% end %>
Here are my routes:
Rails.application.routes.draw do
root 'recipes#index'
This shows up fine when I visit localhost:3000, but when I press the button I'm expecting the controller index method to just return whatever text i typed into the textbox. Unfortunately, I only get:
No route matches [POST] "/"
I know setting the root to recipes#index is causing the failure as my #search variable is not set when the page is opened initially.
I'm wondering if I should have a separate route and method for the GET request and should I just open the main page with the call to localhost:3000 without running any code in the controller? Is this possible?
The problem is that form_tag accepts a Hash as both its first and second argument. If you don't use brackets, it's going to interpret all of it as part of the first argument, and your method: "get" is not applied properly.
Because of this, it defaults to doing a POST request, for which there is no route.
Try this. Because the first argument is no longer a Hash, it should work properly:
<%= form_tag("/", method: "get") do %>
Alternatively, using your code, you can try this:
<%= form_tag({ controller: "recipes" }, { method: "get" }) do %>

Action form_for -> show

URL : /evaluations
I have made a form to select a specific item (a period)
class EvaluationsController < ApplicationController
def index
#periods = Period.all
end
My form :
<% form_for XXXXX do %>
<%= collection_select(:period, :period_id, #periods, :id, :fullname) %>
<%= submit_tag("Valider") %>
<% end %>
I would like the form to go to /evaluations/3 when submited (if the selected period is 3).
When I go manually to /evaluations/3 it works like a charm but I really don't know how to write the form_for to go the right url by submitting the form.
Simple way
Submit period ID to process data, and then redirect to action, which handles
evaluations/:id with :id as parameters.
redirect_to <youraction>(:period => #id)
This should do the trick.
Not so simple way
If you want to change something dynamically on your page after data was submitted - call method and respond with javascript
respond_to do |format|
format.js
end
In javascript response you can put whatever you want - simple redirects or script, which will change page dynamically. It's up to you.
Hope it helps.
you need to use some javascript to update the action of the form
$('#period_period_id').change(function() {
$('form').attr('action', '/evaluations/' + this.value);
})

collection.build of nested attribute through a remote_link does not create params when submitting form

I have the following model:
class Activity < ActiveRecord::Base
has_many :clientships, :dependent => :destroy, :after_add => :default_client_info
accepts_nested_attributes_for :clientships, :allow_destroy => true
end
In my controller, if I perform the following
def new
#activity = IndividualActivity.new(params[:activity])
#activity.clientships.build(:client => Client.first)
...
end
and then save the form, it creates the relevant params and submits successfully.
However, if I chose to call the following through a remote link
#activity.clientships.build(:client => Client.last)
the view is updated with the new clientship record but when I submit the form, the params[:activity] is not created for the second nested attribute. (Why not!?)
This is the view:
%h1 Create a new Activity
- form_for #activity do |f|
%div
= render "activities/client_selector", :f => f
%div
= f.submit "Save!"
Here is the remote_link's controller action
def add_client
#activity = IndividualActivity.new(session[:individual_activity])
# Refresh client
#activity.clientships.build(:client => Client.find(params[:client_id]))
respond_to do |format|
format.js
end
end
This is the add_client.html.js:
page.replace_html "selected_clients", :partial => 'activities/clients'
This is the activities/clients partial:
- form_for #activity do |f|
- f.fields_for :clientships do |client_f|
%tr
%td= client_f.hidden_field :client_id
%td= client_f.object.client.full_name
Does anyone know how I can troubleshoot this further? I seem to have come to a dead-end with my debugging... One thing to note, there is a double use of the following form_for used in new.html.haml and the activities/clients partial (is this problematic?)
- form_for #activity do |f|
I am on rails v2.3.5
Thanks
You ask about debugging, so the first step may be looking at the server log (log/development.log).
There you should see the "params" hash.
Maybe your params contain "activity"=>{"client_id"=>..} instead of "client_id"=>.. ?
Also look at the generated HTML page - use a Firebug or just use a "view source" method of your browser. Look, especially, for input names.
If everything looks OK, put a few debug calls in your action, and look at the development.log for some database activity - do the SQL queries look like they are doing what you want?
In your question there is no 'save' method. The 'build' method does NOT save the created record. Maybe this is your problem?
def add_client
logger.debug "Creating Activity"
#activity = IndividualActivity.new(session[:individual_activity])
logger.debug "Building clientship"
# Refresh client
#activity.clientships.build(:client => Client.find(params[:client_id]))
logger.debug "#activity = #{#activity.inspect}"
# Maybe you were missing this part of code?
logger.debug "Saving #activity"
#activity.save! # use a ! to easily see any problems with saving.
# Remove in production and add a proper if
logger.debug "Saved. #activity = #{#activity.inspect}"
respond_to do |format|
format.js
end
end
You should create a functional test (in case you haven't already) and ensure that if you send proper parameters, your action works as intended.
The test will narrow your search. If the test fails, you know you have a problem in the action. If the test is OK, you need to ensure the parameters are sent properly, and you probably have the problem in your view.
UPDATE:
You said you have TWO forms on the page. This may be the problem, since only one form may be sent at a time. Otherwise it would need to work in a way which can send two requests in one request.
First thing (useful in all similar problems): validate whether your page has correct HTML structure - for example http://validator.w3.org would be a good start. Try to make the code validate. I know that some people treat a "green" status as a unachievable mastery, but just it's really not so hard. With valid code you may be sure that the browser really understands what you mean.
Second: Place all your inputs in a single form. You have problems with nested attributes. For start, try to manually insert inputs with name like <input name="activity[clientship_attributes][0][name]" value="John"/>, and for existing clientships ensure that there is an input with name = activity[clientship_attributes][0][id].
This is the way nested attributes are handled.
Your view may create such fields automagically. This construction should be what you need: (it worked in one of my old project in rails 2.x, I have just replaced the names with ones you use)
<% form_for(#activity) do |f| %>
<p><%= f.text_field :activity_something %></p>
<% #activity.clientships.each do |clientship| %>
<% f.fields_for :clientships, clientship do |cform| %>
<p><%= cform.text_field :name %></p>
<p><%= cform.text_fiels :something %></p>
<% end %>
<% end %>
<% end %>
If you really want to use a partial there, don't create a new form in the partial. Use only the parts of above code.
To pass a variable to the partial, use :locals attribute in the place where you call render :partial:
<%= render :partial => 'clientship', :locals => {:form => f} %>
Then, in your partial, you may use a local variable form where you would use f outside of the partial. You may, of course, map the variables to the same name: :locals => {:f => f}

Rails: Multi-submit buttons in one Form

Say I have an Article model, and in the article 'new' view I have two buttons, "Publish" and "Save Draft".
My question is how can I know which button is clicked in the controller.
I already have a solution but I think there must be a better way.
What I currently used in the view is:
<div class="actions">
<%= f.submit "Publish" %>
<%= f.submit "Save Draft", :name => "commit" %>
</div>
So in the controller, I can use the params[:commit] string to handle that action.
def create
#article = Article.new(params[:article])
if params[:commit] == "Publish"
#article.status = 'publish'
// detail omitted
end
#article.save
end
But I think using the view related string is not good. Could you tell me another way to accomplish this?
UPDATE: Since these buttons are in the same form, they're all going to the 'create' action, and that's OK for me. What I want is to handle that within the create action, such as give the Article model a 'status' column and holds 'public' or 'draft'.
This was covered in Railscast episode 38. Using the params hash to detect which button was clicked is the correct approach:
View:
<%= submit_tag 'Create' %>
<%= submit_tag 'Create and Add Another', name: 'create_and_add' %>
Controller:
if params[:create_and_add]
# Redirect to new form, for example.
else
# Redirect to show the newly created record, for example.
end
it can also be done on the form_for helper like this
<%= f.submit "Publish",name: "publish", class: "tiny button radius success" %>
<%= f.submit 'Mark as Draft', name: "draft", class: "tiny button radius " %>
and the logic is the same on the controller
if params[:publish]
// your code
elsif params[:draft]
// your code
end
We solved using advanced constraints in rails.
The idea is to have the same path (and hence the same named route & action) but with constraints routing to different actions.
resources :plan do
post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end
CommitParamRouting is a simple class that has a method matches? which returns true if the commit param matches the given instance attr. value.
This available as a gem commit_param_matching.
I remember coming across this problem once. You cannot keep two buttons and then call some action based on the params[:commit]. the submit button onclick is going to call the url the form refers to. There are certain bad ways to get the desired behavior. Keep a button to call the action the form refers to and to get another button to call a action, I used a link_to and then changed the styles to match a button. Also, alternatively you can use jQuery to change the url the form would call, hence deciding what action is invoked at run-time. Hope this helps.
You could also set some data attributes on the submit buttons and use JavaScript to change out the form action on click of one of the buttons
usually i using the suggestion given by John Topley (see answer above).
another way is using JQuery /JS changing the form action attribute- upon clicking the submit button
example:
form_tag({} ,:method => 'post', :id => 'reports_action') do
.......
.......
submit_tag 'submit', :onclick => "return changeAction();"
end
and then .....
function changeAction(){
$('#reports_action').attr('action','my_new_action');
}

Resources