Generate select tag from validation options with I18N - ruby-on-rails-3

Is it possible to create a select tag from the models validation without having problems with I18N?
For example if i had a model like this:
Model:
class Coffee < ActiveRecord::Base
SIZES = [ "small", "medium", "big" ]
validates :size, :inclusion => { :in => SIZES,
:message => "%{value} is not a valid size" }
end
Form:
<%= f.label :size %><br />
<%= select(:coffee, :size, Coffee::SIZES.collect {|d| [d, d]}) %>
How can I make this language independent?

The best way to handle that is to have locale-independent values in DB and localized labels on UI. You can achieve that by changing options for your select like that:
<%= select(:coffee, :size, Coffee::SIZES.collect {|d| [I18n.t(d), d]}) %>
and having that in you locale file:
some-language:
small: "small-translation"
medium: "medium-translation"
big: "big-translation"
That will generate html like that:
<select name="coffee[size]">
<option value="small">small-translation</option>
<option value="medium">medium-translation</option>
<option value="big">big-translation</option>
</select>
User will see localized options in select, but in request parameters locale-independent values will be posted, so your validation will work as it should.

If you're trying to make the validation message i18n independent, you don't actually need to mention which size is invalid, just that it is. You're passing an HTML select form, if they chose another size it's more likely they're messing with something so an exact error message is unnecessary.
For the select text itself, you could just pass it to the i18n system and handle it in that. By building the array with Coffee::SIZE.collect {|d| [t(".#{d}"), d]} you could add small, medium, big to your i18n file for that view to get localized values based off your validation options.

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?

How to add html link for a simple_form field in rails 3.2?

Here is the quote_task field in simple form.
<%= f.input :quote_task, :label => t('Quote Task'), :input_html => {:value => #quote_task.id}, :readonly => true %>
Now we want to add an embeded html link for the #quote_task.id to show the content of the quote_task. When a user click the id, he will be directed to the content of the quote task. Something like:
<%= f.input :quote_task, :label => t('Quote Task'), :input_html => {:value => (link_to #quote_task.id.to_s, quote_task_path(#quote_task.id))}, :readonly => true %>
Is there a way to do this in simple_form? Thanks for help.
your expectation for HTML are way beyond any possible semantic.
http://www.w3schools.com/tags/tag_input.asp
http://www.w3.org/html/wg/drafts/html/master/forms.html#the-input-element
Yes it is possible that when one click on a input, it will show desired content. However without JS this wont be possible
input:
<%= f.input :quote_task, :label => t('Quote Task'), :readonly => true, class="redirecter", :'data-quote-task-path'=>quote_task_path(#quote_task.id) %>
coffee script using jQuery:
#app/assets/javascript/my_input.coffee
jQuery ->
$('input.redirecter').click ->
path = $(this).data('quote-task-path')
document.write(path); # ugly redirect, use Ajax
simple solution, but better would be if you load some content from server to your page with Ajax http://api.jquery.com/jQuery.ajax/
but my opinion is that you shouldn't do this at all. Inputs are for forms, forms are for submitting data. What you should be really using is pure link_to without any input due to HTML semantics. If you want it to look like input that you can style it to look like input, point is don't rape input tag for what it not meant to do.
it's not possible to embed anchors within input fields.
you can use javascript to do whatever magic that field should have.
if you want to find out more about javascript. go to amazon, buy a book, read it.

simple_form error messages do not go away

I'm using simple_form with twitter bootstrap on Rails.
Everything works great, except when showing live validations in a form-inline class. My code for the form is:
<%= simple_form_for #message,
url: mailing_list_path,
html: { class: "form-inline" },
method: :post,
validate: true do |f| %>
<%= f.input_field :email_address, label: false %>
<%= f.submit "Submit" %>
<% end %>
This shows the error message properly (e.g. "is invalid"), but if I click off the input and then back on again, it adds another message (e.g. it would say "is invalid is invalid"). For example, two sequential invalid entries and then a blank entry would give:
Is there any way to have simple_form remove the existing error message before adding a new one?
EDIT:
I solved this using some ghetto js, but would still like to know if the functionality I mentioned above is built in. The divs are still there, they're just hidden instead of all showing together. Would be great to have them actually removed by the form validation...
$('input.email-address-input').on 'keyup', () ->
$(this).parent('form').siblings('.help-inline').hide()

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