As far as I know, the accepted way to set the "humanized" names of fields in Rails 3 is to use locales:
# config/locales/en.yml
en:
activerecord:
attributes:
member:
username: 'username' # rather than 'Username'
However, I simply want Rails 3 to use lowercase versions of its default humanized names. Is there an easy, built-in way to do this?
An example to help clarify: When inside of a form_for, <%= f.label :username %> displays "Username" by default. I want it to display "username".
I had the same problem.
I solved it via css:
In foo.html.erb:
<%= f.label :username, :class => "my_class" %>
In bar.css:
label.my_class {
text-transform: lowercase;
}
I would prefer a different solution, too. But that's the only one I've been able to find, so far.
The label helper defaults to using human_attribute_name to turn an attribute into a human name. If you look at the source, human_attribute_name tries a few things before falling back to attributes.to_s.humanize. It tries the translation first, and then it looks for a :default option in the options hash.
So, the simplest/best way to get the functionality you want is to override human_attribute_name with your own that provides a :default option and then calls the original. Rails provides a reasonable way to do this sort of thing with alias_method_chain, so...
I've heard enough, just give me the answer!
Put the following in any file in config/initializers and restart your app:
module ActiveModel
module Translation
def human_attribute_name_with_foo attribute, options = {}
human_attribute_name_without_foo attribute, options.merge( :default => attribute.humanize.downcase )
end
alias_method_chain :human_attribute_name, :foo
end
end
Related
Using globalize gem to manage translations with autocomplete, there is a situation where a number of hooks need to be properly set. Note: this does not use hstore AFAIK. I have not managed to find a way to do so. The most productive set-up to date has
controller:
autocomplete :nation, :name, :full => true
Nation
translates :name
view
<%= autocomplete_field_tag 'nation_name', '', autocomplete_nation_name_itins_path, size: 35, :id_element => 'nation_id' %>
There is no inherent reference to nation_translations database table created by Globalize as of yet. As this image suggests, there is a problem:
Issue 1: The input remains binded to the base table's attribute value (I have not yet cleared them out as the Globalize gem suggests. Otherwise I'd be getting blanks). can is actually ready all values of canin master table... Typing in other locales, like cyrillic say Канада has naturally no effect as that value is not part of the Nation table.
What is interesting is that the drop-down values are being populated by Rails automatically, extracting the translation values of what is input.
Issue 2: I'd rather pass the parameter 'nation_id' which is naturally part of the nation_translations table with the form data. although I can append , :extra_data => [:nation_id] to the controller it is not being submitted (example in cyrillic where the input is given without any autocomplete)
{"utf8"=>"✓", "nation_name"=>"Канада", "commit"=>"..."}
Rails.logger.info :extra_data returns:
extra_data
Now the second issue can be overcome because a query like
Nation::Translation.where('name = ?', "Канада").pluck('nation_id')
returns a proper result. But that point is moot if the autocomplete is not playing ball with the user's input.
How can this be configured to have user input autocomplete with the current local translations?
this does get solved by creating an entirely new class with attributes nation_id, name, locale and can thus be called symbolically.
The query call is not that straightforward however. As the gem suggests, the method need to be tweaked
def autocomplete_nation_name
term = params[:term].downcase
locale = params[:locale]
nationtranslations = Nationtranslation.where('locale = ? AND name LIKE ?', locale, "%#{term}%").order(:name).all
render :json => nationtranslations.map { |nationtranslation| {:id => nationtranslation.id, :label => nationtranslation.name, :value => nationetranslation.name} }
end
intervening on the action method itself provides all the leeway desired...
I would like to make editing form fields as user-friendly as possible. For example, for numeric values, I would like the field to be displayed with commas (like number_with_precision).
This is easy enough on the display side, but what about editing? Is there a good way to do this?
I am using the Rails FormBuilder. Upon investigation, I found that it uses InstanceTag, which gets the values for fields by using <attribute>_value_before_type_cast which means overriding <attribute> won't get called.
The best I have come up with so far is something like this:
<%= f.text_field :my_attribute, :value => number_with_precision(f.object.my_attribute) %>
Or my_attribute could return the formatted value, like this:
def my_attribute
ApplicationController.helpers.number_with_precision(read_attribute(:my_attribute))
end
But you still have to use :value
<%= f.text_field :my_attribute, :value => f.object.my_attribute %>
This seems like a lot of work.
I prefer your first answer, with the formatting being done in the view. However, if you want to perform the formatting in the model, you can use wrapper methods for the getter and setter, and avoid having to use the :value option entirely.
You'd end up with something like this.
def my_attribute_string
foo_formatter(myattribute)
end
def my_attribute_string=(s)
# Parse "s" or do whatever you need to with it, then set your real attribute.
end
<%= f.text_field :my_attribute_string %>
Railscasts covered this with a Time object in a text_field in episode #32. The really clever part of this is how they handle validation errors. It's worth watching the episode for that alone.
This is an old question, but in case anyone comes across this you could use the number_to_X helpers. They have all of the attributes you could ever want for displaying your edit value:
<%= f.text_field :my_number, :value => number_to_human(f.object.my_number, :separator => '', :unit => '', :delimiter => '', :precision => 0) %>
There are more attributes available too: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
If you want a format to be created or maintained during editing, you will need to add Javascript to implement "masks." Here is a demo.
It was the first hit in these results.
You can use the number_format plugin. By specifying a number_format for an existing numeric attribute inside your model, the attribute will now appear as formatted to Rails in all forms and views. It will also be parsed back from that format (when assigned via forms) prior to insertion into the database. (The plugin also creates purely numeric unformatted_<attribute-name> accessors which can continue to be used for arithmetic, or for direct numerical assignment or retrieval by you for seamless integration.)
class MyModel < ActiveRecord::Base
# this model has the balance attribute, which we
# want to display using formatting in views,
# although it is stored as a numeric in the database
number_format :balance,
:precision => 2,
:delimiter => ',',
:strip_trailing_zeros => false
def increment_balance
unformatted_balance += 10
end
You can also combine the above with a Javascript solution, which can force the user to maintain the decimal point and thousands separators in place while editing, although this is really not necessary.
I have done something similar. We format times and lengths using a custom form builder. It makes use of the existing text_field, but wraps it so the value can be customized:
class SuperFormBuilder < ActionView::Helpers::FormBuilder
include ApplicationHelper
include FormHelper
include ActionView::Helpers::TagHelper
include ActionView::Helpers::FormTagHelper
def length_field(label,*args)
scale = 'medium'
args.each do |v|
if v.has_key?(:scale)
scale = v[:scale]
v.delete(:scale)
end
end
value = length_conversion(#object.send(label.to_sym),scale)
options = (args.length > 0) ? args.pop : {}
return has_error(label, text_field_tag(field_name(label),value,*args) + ' ' + length_unit(scale))
end
private
def field_name(label)
return #object_name + "[#{label}]"
end
def has_error(label, output)
return "<div class='fieldWithErrors'>#{output}</div>" if #object.errors[label]
return output
end
And it is used like this:
<%= form_for( #section, {:action => 'save', :id => #section.id}, :builder => SuperFormBuilder) do |sf| %>
<%= sf.length_field :feed_size_min_w, :size => 3, :scale => 'small' %>
<% end %>
The end result is a value in the appropriate unit based off their choice on system (Metric, Imperial) and scale IE small = inches or millimeters.
I basically copied the text_field method from the existing form builder, which uses the text_field_tag itself.
There are two gotchas: 1) Knowing the name of the object field and how to access the object to get the value which you want to format. 2) Getting the name right so when the form is submitted it is part of the correct params hash.
The form builder is given a class variable #object. You can get the value of the field using the .send method. In my case I send the label :feed_size_min_w to the #object and get its length back. I then convert it to my desired format, and give it to the text_field_tag.
The name of the field is key to having it end up in the params hash, in my instance the params[:sections] one. I made a little helper function called field_name that takes care of this.
Finally the has_error wraps the field in an error div if there are errors on that label.
I needed "nicer" format on some specified text fields, resolved it by adding this to my initializers. Seems to work nicely on Rails ~= 5.2 and it should be easy to customize.
class ActionView::Helpers::Tags::TextField
private
def value_before_type_cast # override method in ActionView::Helpers::Tags::Base
v = super
# format as you like, when you like
if #options.delete(:nice_decimal)
v = v.to_s.gsub('.', ',') if v.is_a?(BigDecimal)
end
v
end
end
Usage in form f
<%= f.text_field :foo, nice_decimal: true %>
I have the following haml code in index.haml
%h1.content-header{id: 'content-header'} HEADER
%section.form
%form.standard{action: some_path, method: 'get'}
%fieldset.search{'aria-labelledby' => 'content-header'}
%input{type: 'search', name: 'name', placeholder: 'something', role: 'textbox'} -----(6)
%fieldset.input-actions
%input.primary-action{type: 'submit', value: 'search' , name: 'invokeSearch'}
I have the following in my controller
def index
Rails.logger.debug "#{params[:name]}"
unless #invalid_characters
unless params[:name].blank?
....
....
....
The issue is if i change the name: 'name' in line 6 to say name: 'test' .... params[:test] is always blank in my controller. But if i use name: 'name' , params[:name] seems to work . No clue what i am doing wrong here
If you are using rails you should probably benefit from using one of the form helpers for generating the form. For example forms_for that makes you access things in your model directly. It may look like this.
= forms_for #thing do |f|
= f.text_field :name
= f.text_field :test
= f.submit
In this case there will be a map for the model instance in the params map. Something like
params[:thing][:name]
or
params[:thing][:test]
you can take that map and pass it into a model to create or update it. If you don't want the tight coupling with the model there is the form_tag method that does much the same thing except you need to be more explicit in what value goes where. And fields ends up directly in params instead of in a model hash.
To see how your params come in you can use the inspect method.
puts "params: #{params.inspec}"
or install pry to set a break point with
binding pry
Some ideas. Hope it works out for you. I think you should start with trying to use the rails forms helpers and it will probably sort itself out.
I'm new to ruby on rails, and I installed devise on my application. I was wondering where I can customize the values if a value is given in views/devise/registrations/new.html.erb
for example:
<%= f.input :password_confirmation, :required => true %>
this gives out an input and a label, the label is * Password confirmation. How do I customize this label and the input field?
Thanks
<%= f.input :password_confirmation, :required => true, :label => 'something', :class => 'something' %>
Define the something class in CSS and you'll be fine.
And of course, generate the partials via copying from devise directly or using its generators. I usually copy them from devise repo since I am not that much fan of generators, sometimes they generate files I don't even need or want.
rails generate devise:views users
You will need to generate the partials first. After that you can use those generated files to override the default ones. Also, it might be good to build the authentication from scratch the first time in order to better understand the process.
http://railscasts.com/episodes/250-authentication-from-scratch
I would like to make editing form fields as user-friendly as possible. For example, for numeric values, I would like the field to be displayed with commas (like number_with_precision).
This is easy enough on the display side, but what about editing? Is there a good way to do this?
I am using the Rails FormBuilder. Upon investigation, I found that it uses InstanceTag, which gets the values for fields by using <attribute>_value_before_type_cast which means overriding <attribute> won't get called.
The best I have come up with so far is something like this:
<%= f.text_field :my_attribute, :value => number_with_precision(f.object.my_attribute) %>
Or my_attribute could return the formatted value, like this:
def my_attribute
ApplicationController.helpers.number_with_precision(read_attribute(:my_attribute))
end
But you still have to use :value
<%= f.text_field :my_attribute, :value => f.object.my_attribute %>
This seems like a lot of work.
I prefer your first answer, with the formatting being done in the view. However, if you want to perform the formatting in the model, you can use wrapper methods for the getter and setter, and avoid having to use the :value option entirely.
You'd end up with something like this.
def my_attribute_string
foo_formatter(myattribute)
end
def my_attribute_string=(s)
# Parse "s" or do whatever you need to with it, then set your real attribute.
end
<%= f.text_field :my_attribute_string %>
Railscasts covered this with a Time object in a text_field in episode #32. The really clever part of this is how they handle validation errors. It's worth watching the episode for that alone.
This is an old question, but in case anyone comes across this you could use the number_to_X helpers. They have all of the attributes you could ever want for displaying your edit value:
<%= f.text_field :my_number, :value => number_to_human(f.object.my_number, :separator => '', :unit => '', :delimiter => '', :precision => 0) %>
There are more attributes available too: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
If you want a format to be created or maintained during editing, you will need to add Javascript to implement "masks." Here is a demo.
It was the first hit in these results.
You can use the number_format plugin. By specifying a number_format for an existing numeric attribute inside your model, the attribute will now appear as formatted to Rails in all forms and views. It will also be parsed back from that format (when assigned via forms) prior to insertion into the database. (The plugin also creates purely numeric unformatted_<attribute-name> accessors which can continue to be used for arithmetic, or for direct numerical assignment or retrieval by you for seamless integration.)
class MyModel < ActiveRecord::Base
# this model has the balance attribute, which we
# want to display using formatting in views,
# although it is stored as a numeric in the database
number_format :balance,
:precision => 2,
:delimiter => ',',
:strip_trailing_zeros => false
def increment_balance
unformatted_balance += 10
end
You can also combine the above with a Javascript solution, which can force the user to maintain the decimal point and thousands separators in place while editing, although this is really not necessary.
I have done something similar. We format times and lengths using a custom form builder. It makes use of the existing text_field, but wraps it so the value can be customized:
class SuperFormBuilder < ActionView::Helpers::FormBuilder
include ApplicationHelper
include FormHelper
include ActionView::Helpers::TagHelper
include ActionView::Helpers::FormTagHelper
def length_field(label,*args)
scale = 'medium'
args.each do |v|
if v.has_key?(:scale)
scale = v[:scale]
v.delete(:scale)
end
end
value = length_conversion(#object.send(label.to_sym),scale)
options = (args.length > 0) ? args.pop : {}
return has_error(label, text_field_tag(field_name(label),value,*args) + ' ' + length_unit(scale))
end
private
def field_name(label)
return #object_name + "[#{label}]"
end
def has_error(label, output)
return "<div class='fieldWithErrors'>#{output}</div>" if #object.errors[label]
return output
end
And it is used like this:
<%= form_for( #section, {:action => 'save', :id => #section.id}, :builder => SuperFormBuilder) do |sf| %>
<%= sf.length_field :feed_size_min_w, :size => 3, :scale => 'small' %>
<% end %>
The end result is a value in the appropriate unit based off their choice on system (Metric, Imperial) and scale IE small = inches or millimeters.
I basically copied the text_field method from the existing form builder, which uses the text_field_tag itself.
There are two gotchas: 1) Knowing the name of the object field and how to access the object to get the value which you want to format. 2) Getting the name right so when the form is submitted it is part of the correct params hash.
The form builder is given a class variable #object. You can get the value of the field using the .send method. In my case I send the label :feed_size_min_w to the #object and get its length back. I then convert it to my desired format, and give it to the text_field_tag.
The name of the field is key to having it end up in the params hash, in my instance the params[:sections] one. I made a little helper function called field_name that takes care of this.
Finally the has_error wraps the field in an error div if there are errors on that label.
I needed "nicer" format on some specified text fields, resolved it by adding this to my initializers. Seems to work nicely on Rails ~= 5.2 and it should be easy to customize.
class ActionView::Helpers::Tags::TextField
private
def value_before_type_cast # override method in ActionView::Helpers::Tags::Base
v = super
# format as you like, when you like
if #options.delete(:nice_decimal)
v = v.to_s.gsub('.', ',') if v.is_a?(BigDecimal)
end
v
end
end
Usage in form f
<%= f.text_field :foo, nice_decimal: true %>