How do I set two different actions from a rails form? - ruby-on-rails-3

I have a rails form that creates (and updates) materials. Obviously, by default, when the user is logged in and the materials is retrieved the form renders with the update action. However, I want to have a "save as" action in case the user wants to save another version of the material. The obvious way to do this is to have one button which sends to 'update' in the controller and another which sends to 'new', but I don't know how to do this since it seems to depend on the form_for parameters.
Update
To avoid using Javascript I tried changing the form_for url to:
<%= form_for #material, :url => choose_action_path do |f| %>
Then in the controller I have:
def choose_action
if params[:save_as] == "Save As"
redirect_to :action => "create"
else
redirect_to :action => "update"
end
end
but this is not working. Is this a strategy that could work or is this crazy?

You could probably do this with some jquery.
Let's say the model you are working on is called Email. When you edit an Email, the form tag that is created with have an action action='/emails/:id and a method method='post'. Hidden underneath the form tag is something like
<form accept-charset="UTF-8" action="/email/1" method="post">
<div style="margin:0;padding:0">
<input name="_method" type="hidden" value="put" />
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
</div>
more info can be found here: http://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-put-or-delete-methods-work
That extra chunk of code makes the form submit a put request instead of a post, which subsequently maps to the update action of your controller. To get it to send the form to the create action, you want to post the action "/email". In other words, you want to manipulate the code above into something like
<form accept-charset="UTF-8" action="/email" method="post">
Note the removal of the div tag.
So my suggestion would be to create a button "Save As", then add some jquery which will make those modifications when the "Save As" button is clicked.
This stackoverflow answer might help you with the jquery Jquery to change form action

Related

Rails 5: Search form not preserving locale url parameter

I have a search form on my home page (root_path) that returns the results to the root_path as well. I am making a multilingual site using Ruby I18n and am using the url parameters option, so that the language is specified like so: localhost/?locale=en
For some reason, when submitting the search form, the response is not in the chosen language (it is in the default language), and the locale parameter is now gone from the URL. For example, submitting with localhost/?locale=ja will return with an English page and a URL of localhost/(other search from parameters but no locale)
All other parts of my application preserve the locale parameter correctly (e.g. link_to). Other forms in my application also preserve it correctly when submitted.
There are only two differences I can see between this form and the others.
This form uses method:get
This form is on the root_path
Here is the form:
<%= form_with(url: root_path, local: true, method: :get) do |form| %>
(various fields)
<%= form.submit t(:submitsearch), name: nil %>
The html that is generated:
<form action="/?locale=en" accept-charset="UTF-8" method="get">
<input type="submit" value="Search" data-disable-with="Search" />
application_controller
class ApplicationController < ActionController::Base
before_action :set_locale
def default_url_options
{ locale: I18n.locale }
end
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
However the url that is requested is:
http://localhost:3000/?utf8=✓&(other parameters - no locale)
Here's an example from my app that behaves as expected
<%= form_with model: #equipment_type, local: true do |form| %>
(various fields)
<%= form.submit %>
which has generated html of
<form action="/equipment_types/2?locale=en" accept-charset="UTF-8" method="post">
<input type="submit" name="commit" value="Update Equipment type" data-disable-with="Update Equipment type" />
I basically need the search form to preserve the user's chosen language, but at the moment it is always reverting to the fallback (and the locale parameter is disappearing from the URL). The form action seems to be getting generated correctly (it has the ?locale=en parameter), but it is not in the request URL or response.
Can anyone suggest what the problem might be here?
So after a bit more research, the link here suggests that this is default behaviour of browsers and that it is per HTML spec. That is, any query string parameters in the action of a form will be entirely replaced. For rails, that means if you have a form with action GET, even though rails puts the locale parameter in the form action, it will not get used and you will lose the chosen locale (and revert to the default).
As a solution, you can add the following tag to your form:
<%= hidden_field_tag "locale", params[:locale]%>
Which will add the parameter back into the form submission. It's not perfect, because the locale parameter now appears after the UTF8 one (e.g. ?utf8=✓&locale=en) whereas in all other cases, the locale parameter will appear first. Though this is only a minor point.

Rails 5 - use collection_radio_buttons to open a partial with nested models?

(my first SO question, so please be kind!)
Each Schedule has only one System;
Each System has many Applications;
Each Application has many Users and Documents.
What I want to do to create a Schedule entry:
Generate a form that first shows multiple System names that can be clicked. When a System is clicked, it opens a partial that lists Applications associated with that System. Then, when clicking particular Applications, yet another partial opens that contains Users and Documents associated with that particular Application.
When editing this entry later, I want to be able to see everything I had entered before, with the correct System, Application(s), User(s), and Document(s) already pre-selected.
My question here is how to make a form element for choosing a System that will open another partial -- and, later, will be pre-selected when I view and/or edit the entry.
What kinda works right now is a <%= link_to %>, styled with Bootstrap, which opens its associated Applications partial when it's clicked. However, I'm not able to save the System from it, and I can't figure out whether it can display as already-selected later, such as in an Edit form.
We're trying to use radio buttons instead (because you can't pre-select a link_to, right?), so I've been throwing pasta at the wall with f.collection_radio_buttons, or iterating over f.radio_button, or a tag of <input type="radio">. However, I can't figure out how to make a radio button open a partial.
Since first posting this question, I've narrowed down to using f.radio_button within a loop. It shows as correctly "checked" when viewed while Editing the entry later, but it still doesn't open the partial.
Here's a snippet from /_schedule_form.html.erb:
<%= form_for #schedule do |f| %>
<% System.all.each do |a| %>
<!-- This link_to makes the Applications partial appear, but that's all it does -->
<%= link_to a.system_nm, system_applications_path(:system_id => a.id,
:schedule_id => params['id']), :title => 'Click to choose system',
:class -> 'btn btn-default btn-flat active', data: {:remote => true,
'data-target' => '#applicationList'} %>
</a> <!-- closes the link_to tag, I believe -->
<% end %>
<div id="applicationList">
<!-- the Applications partial renders here -->
</div>
<% end %>
Here's the system_applications.js.erb file that opens the _system_applications.html.erb partial:
$("#applicationList").html("<%= escape_javascript(render
'system_applications', locals: {applications: #applications,
schedule_applications_array: #schedule_applications_array})%>");
Here's an update with possible clue:
I'm now using this embedded Ruby code:
<% System.all.each do |rt| %>
<label>
<%= f.radio_button :system_id, rt.id, data:{:remote => true, 'data-target' =>
'#applicationList'}, href: system_applications_path(:system_id => rt.id,
:schedule_id => params['id']), class: 'remote-input', onclick:
"#applicationsList" %>
</label>
<% end %>
And, when I click on that radio button, I'm getting a JS error in the browser console Uncaught SyntaxError: Invalid or Unexpected Token which points to the rendered HTML, and specifically the > at the end of the line:
<input data-remote="true" data-data-target="#applicationList" href="/schedules/system_applications/24?schedule_id=122" class="remote-input" onclick="#applicationList" type="radio" value="24" checked="checked" name="schedule[system_id]" id="schedule_system_id_24" />
Just to make it more complicated:
When creating a NEW entry, and when I hover over one of the link_to buttons, I get a clean-looking path like /schedules/system_applications/24, and that's what gets sent to the server when clicked (which then reads the params as {"system_id"=>"24"}. But hovering over the f.radio_button labels shows no path, and clicking it sends "/schedules/new?schedule%5Bsystem_id%5D=24" with the params {"schedule"=>{"system_id"=>"24"}}. This triggers a 500 (Internal Server Error) (which makes sense, because there's no path for that URL). Do the params need to be the same? If so, how am I screwing it up?
Also, clicking the radio button sends the request to SchedulesController#new, while clicking the link_to sends it to SchedulesController#system_applications. I don't understand how I'm telling the radio button to send it to #new.
Where I'm stuck now is, the f.radio_button renders as "checked", which is correct; but it doesn't open the partial. The link_to version opens the partial, but I don't think it can render as "checked" later on.
Let me know if I'm asking clearly enough, too.
I think we made it work. One key change was to use url instead of href to use the system_applications_path to the controller, as shown here:
<% #systems.each do |a|
<label class="btn btn-sm btn-default">
<%= f.radio_button :system_id, a.id, :data => {url:system_applications_path(:system_id
=> a.id, :schedule_id => params['id']), 'data-target' => '#applicationList'+a.id.to_s,
:remote => true} %>
<%= a.system_nm %>
</label>
<% end %>
Now, when I click the radio button, it opens the correct partial, and it shows as selected later when I go to edit the entry. The Bootstrap styling (btn btn-sm btn-default) helps to show how much clickable area there is, but it's not required for basic functionality.
I suppose some of that [in]famous Rails Magic has radio_buttons treating href: differently than url. But it's "magic" only because I don't understand it (yet -- growth mindset!). What's the explanation behind it?

Active Admin Search/Filter widget on Custom Page

I want to have a search widget/filter feature on a custom page using active admin to provide a look-up feature. Using the action_items I have my own action and form that renders the search page. On the search page the 'filters' that I need to show include text fields of the 'Parent' resource and a drop down list of the Parent's Parent. The association is as follows
Class MyChildResource
belongs_to :myParentResource
Class MyParentResource
attr_accessible :name, :close_to_place, :date
has_many :myChildResources
belongs_to :myGrandParentResource
class MyGrandParentResource
has_many :myParentResources
In the active admin Resource
ActiveAdmin.register MyChildResource do
action_item :only=>:index do
link_to("Look Up Availability", search_admin_myChildResources_path)
end
collection_action :search do
# do something here similar to the 'filter' feature like filter on myparentresource.date as date
filter on myGrandParentResource as drop down
filter on myParentResource.close_to_place as string
end
end
Do I have to write my own custom meta_search features? I would be fine even if I have to write own search queries, based on the input that the user gives, but my problem is that how do I display the drop down values from the parent's parent model and/or leverage the power of active admin filters.
I read something similar in this question,How to add a filter to Active Admin dashboard? , but it's a hack and it definitely does not answer the question of displaying a list
I haven't found any DRY way of doing this, so I've ended up creating my own search form which uses the active admin css for the 'sidebar' and 'panel' as mentioned in the link above and for each element of drop down, text field , date and buttons. So I get a widget which looks like the sidebar.
For the search result, I am running my own queries and searching based on the user input.
The Search Form looks like this:
Search For <br>
<div id="search_filter_partial" class="panel_contents">
<%= form_tag(search_path,:remote=>true,:class=>"filter_form", :name=>"search_filters") do %>
<div class="filter_form_field filter_string">
<%= label_tag(:author, "Author",:class=>" label") %>
<%= text_field_tag (:author) %>
</div>
<div class="filter_form_field filter_select">
<%= label_tag(:book, "Book",:class=>" label") %>
<%= select("book","book_id", #books.map {|u| [u.name,u.id]}) %>
</div>
<div class="filter_form_field filter_string">
<%= label_tag(:published_date, "Published Date",:class=>"label")%>
<%= date_select :book,:published_date %>
</div>
<div class="buttons">
<%= submit_tag('Find It', :onclick => "validateForm();") %>
<a class="clear_filters_btn" href="#">Clear</a>
<input id="order" type="hidden" value="id_desc" name="order">
<input id="scope" type="hidden" name="scope">
</div>
<%end%></div>
Doesn't look too good, but that's the best I have been able to come up with since I want to stay consistent with the look and feel of Active Admin

Rails Trying to submit a form onchange of dropdown

I have my Ajax working, builtin Rails javascript, with the submit button. However, I would like it to submit when I change the value of the dropdown box and eliminate the button. In my research I found what looks like the correct solution but I get no request to the server. Here is my dropdown form code, note it still has the submit button that worked before I added :onchange:
<% form_tag('switch_car', :method => :put, :remote => true) do %>
<div class="field">
<label>Car Name:</label>
<%= select_tag(:id, options_from_collection_for_select(active_cars, "id", "name"),
:onchange => ("$('switch_car').submit()"))%><%= submit_tag "Switch Car" %>
</div>
<% end %>
Here is the HTML generated:
<form accept-charset="UTF-8" action="switch_car" data-remote="true" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="put" />
<input name="authenticity_token" type="hidden" value="PEbdqAoiik37lcoP4+v+dakpYxdpMkSm7Ub8eZpdF9I=" />
</div>
<div class="field">
<label>Car Name:</label>
<select id="id" name="id" onchange="$('switch_car').submit()">
<option value="9">Truck</option>
<option value="10">Car</option>
</select>
<input name="commit" type="submit" value="Switch Car" />
</div>
Thanks in advance for any help.
Replace your onchange with this,
onchange: "this.form.submit();"
this.form.submit() will not work if form is remote: true and rails-ujs is in use. In that case, a regular submit will occur instead of XHR.
Instead you should:
onchange: 'Rails.fire(this.form, "submit")'
You can read here for more details.
This is what I was able to do to get it to work. I named the form switch_car by using :name => "switch_car" and used the following javascript.
:onchange => ("javascript: document.switch_car.submit();")
I am still looking for a better answer so I will updated if I find something. This doesn't use submit .js for some reason. It processes it as HTML unlike the submit button which uses AJAX to update only the changing page elements. But this is the best I have been able to find so far.
Depending on the js library you are using:
Prototype: :onchange => ("$('switch_car').submit()")
Jquery: :onchange => ("$('#switch_car').submit()")
If you are using the defaults and your rails version is below 3.1, then prototype is the default library.
This is an old question, but none of the above answers work for me. They all result in a text/html request.
The following works, e.g. (the hide class sets css display: none):
<%= form.radio_button :tier_id, tier.id, onchange: "$('#submit-button-id').click();" %>
together with:
<%= form.submit "Save changes", id: 'submit-button-id', class: 'hide' %>
A more general solution using jQuery (I don't need to know the name of the form) is:
onchange: "$(this).parent('form').submit();"
This seems to have been around for a while but, I'll post my findings anyway since I haven't found this explanation anywhere yet.
I came across this article which describes quite well what's the problem when triggering a ajax request via the submit() method (with or without jQuery or Handler). The author then recommends to form your own AJAX request. That is not required and shouldn't be done to make use of the logic within rails.js (jquery-jus gem).
Problems with triggering submit() manually occur since rails.js binds and listens to an event that is namespaced submit.rails. To manually trigger a submission use
onchange: 'javascript: $( this ).trigger("submit.rails")'
on the element or the form.
For a select_tag, just add:
{:onchange => "myHandler();" }
where your handler will be:
this.form.submit();
Also, if onchange doesn't work you might want to try onChage with a capital C.
Finally, make sure NOT TO CONFUSE a select_tag with a form select.
See my answer to a similar question, only regarding a form select
Adding An Onchange Event To A Form Select
Time at 2021, with Rails 6
make a hidden submit then use js click() function:
<%= form_with(modle: #user, local: false) do |f| %>
<%= f.select :menu1, ["option1","option2"], {}, onchange: "javascript:this.form.commit.click();" %>
<%= f.submit 'save', class: "hidden" %>
<% end>
reference: https://stackoverflow.com/a/8690633/15461540
If you want to learn rails way ajax submit on fields change here is the code.
<%= select_tag(:id, options_from_collection_for_select(active_cars, "id", "name"),
data: { remote: true, url: your_ajax_route_path }%><%= submit_tag "Switch Car" %>
data: { remote: true, url: your_ajax_route_path }
will automatically submit your input to your_ajax_route_path. If you are using a form builder then you should use with input_html
input_html: { data: { remote: true, url: your_ajax_route_path } }
like this. I hope it'll be useful for you
None of the solutions was working for me so I used the given below solution.
$("#q_dimension_id_eq").on("change", function (e) {
$(this).closest("form").submit();
});
I'm using rails 4.2.1 with jquery_ujs and it works for me:
onchange: 'jQuery(this).parent().trigger("submit")'
OBS.: It assumes the element is immediately child from form. You must adjust parent() according your DOM tree.

devise redirecting to login and signing out user on form post

devise 1.2
rails 3.0.5
I have this in my controller: before_filter :authenticate_user!
When a form is submitted, i'm redirected to the log in page and the user is automatically logged out. Even though they have logged in, this seems to be happening on form post. This is the action that has the issue:
def next
myObject = theObject.first
myObject.current_number = params[:next_number]
myObject.save!
redirect_to :action => 'index'
end
In my view:
%form{:method => "post"}
%input#nextNumber{:name => "next_number", :type => "hidden", :value => "7"}/
Triggered in js as follows:
$("form").submit();
Any ideas why this would be happening? Can't find any useful info...
Looks like you may have solved your problem in another manner but I hit a similar issue that ended up being related to a missing authenticity token on my form. The view was not using the Rails form_for helper, and as a result had no authenticity_token included in the form submission.
ie.
<form action="..." method="POST">...</form>
changed to
<%= form_for :form, :url => "..." do |f| %> ... <% end %>
results in
<form action="..." method="POST">
<input name="authenticity_token" type="hidden" value="...">
...
</form>
More details on authenticity_token: Understanding the Rails Authenticity Token