I've successfully created my he.yml to localize my model's attributes names,
example:
attributes:
vendor:
name: שם ספק
counter_number: מספר חשבונית
phone: טלפון
address: כתובת
Now, displaying labels in forms using simple_form's f.input, displays it correctly, the translated value of each attribute.
the problem is, displaying errors after validation, using
<% #vendor.errors.each do |attribute, error| %>
|attribute| for error "counter_number" for example, is displayed: "counter_number".
not the translated one at the locale file [which as i mentioned previously, configured and loaded successfully].
I appended errors in a ul.errors, as shown in this screenshot:
Thanks in advance.
You can do something like this:
#vendor.errors.messages do |attribute, errors|
translated_attribute = Vendor.human_attribute_name(attribute)
errors = errors.join(", ")
end
I've tested this with my User model:
The following is just an example to complete your provided code.
<% #vendor.errors.each do |attribute, error| %>
<strong><%= t("activerecord.attributes.#{#vendor.class.to_s.underscore}.#{attribute}") %>:</strong>
<%= error.messages.to_sentence %>
<% end %>
Maybe there is an easier approach than this.
Related
I have a form tag which acts as a search form.
I have a set of locations - params: name and id, which Im displaying as collection boxes in the form tag. The search tag displays people for each location who can then be added to the project. By choosing a location on the form tag, you can filter down people for just that particular location.
The search form works fine and Correctly gives me people at each location
Here is what is in the view
<%= collection_check_boxes(#locations, :location_ids, #locations.all, :id, :name) %><br>
Here is the form tag it's enclosed in:
<%= form_tag interviewers_tenant_project_path(#project, tenant_id: #tenant.id), method: :get do %>
Locations are project specific, and I'm creating an instance variable to return all the locations valid for a project.
My problem is that after the form returns the data, the previously selected location check box is not ticked.
Here is my code in the controller
#locations = Location.where("name in (?)", project_locations)
#locations.each do |loc|
puts "loc.name #{loc.name}, #{loc.id}"
def loc.location_ids
[1]
end
end
def #locations.location_ids
puts "ENTER #locations.location_ids "
#location_values
[1]
end
the documentation says this:
collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
"Returns check box tags for the collection of existing return values of method for object's class. The value returned from calling method on the instance object will be selected. If calling method returns nil, no selection is made."
So I've tried adding a method to the object (singleton method) and then when that didn't work, I tried adding a method to each active record instance.
I have hardcoded the value [1] - which corresponds to the first location in my database. But I just cannot make the checkbox selected when the form is re-rendered after the search.
Im new to rails - about 2 months into my project - before that a month studying RoR, so all insights would be beneficial.
Thanks for your help and time
I worked around this finally. I didn't want to re-write the controller. So I tried adjusting the names of the check boxes to the same names as those generated by the collection tag. I have also put 3 extra lines of code, starting with <% param ... which helped me debug the right value. I guess rails experts would call it an ugly hack ... ? Anyways, the check boxes work fine and I didnt have to touch the controller code.
<% #locations.each do |loc| %>
<%= params.has_key?(:location) %>
<%= params.has_key?(:location) && params[:location].has_key?(:location_ids) ? params[:location][:location_ids].to_s : "empty" %>
<%= params.has_key?(:location) && params[:location].has_key?(:location_ids) && params[:location][:location_ids].include?(loc.id) %>
<%= check_box_tag("location[location_ids][]" , loc.id, params.has_key?(:location) && params[:location].has_key?(:location_ids) && params[:location][:location_ids].include?(loc.id.to_s) ? loc.id : nil, id: "location_" + loc.id.to_s) %>
<%= label_tag("location_" + loc.id.to_s, loc.name) %>
<% end %>
I want to implement a search functionality in my Rails app by using the pg_search gem. I've set up everything like it says in the documentation. Then I've set up a search controller with a show action:
def show
#pg_search_documents = PgSearch.multisearch(search_params)
end
The search itself works but I have a really annoying problem in my view. Whatever I do, it always outputs an array of PgSearch::Document objects. Even when I only write this in my view:
<%= #pg_search_documents.each do |document| %>
<% end %>
I get this (I've shortened it):
[#<PgSearch::Document id: 2, content: "…", searchable_id: 28, searchable_type: "Vessel">, #<PgSearch::Document id: 3, content: "…", searchable_id: 27, searchable_type: "Vessel">]
I know that pg_search sets up a polymorphic association which I've never dealt with before — could that be the problem?
Thanks in advance
<%= #pg_search_documents.each do |document| %>
<% end %>
This is a classic error, one I remember being puzzled over when I first started learning Rails. The mistake is using <%= %> with each. The return value of each is the array that you're iterating over (in this case, #pg_search_documents), and by using <%=, you're telling Rails to create a string from that array and insert it into your view. That generally isn't what you want: you want the view to be generated by the code inside the block you're passing to each.
Use <% #pg_search_documents.each do |document| %> instead (omitting the =) and you'll avoid the dump of the array's content.
You may also need to use .searchable as #blelump suggests, but I wanted to answer the other half of your question, as it's a common pitfall.
To get back to the original source model, searchable call is needed on these search result records, e.g:
<% #pg_search_documents.each do |document| %>
<%= document.searchable %>
<% end %>
You can also switch back to the source model within your controller, e.g:
#pg_search_documents = PgSearch.multisearch(search_params).collect(&:searchable)
Then, the #pg_search_documents will contain Vessel elements.
One of the most common reasons my web application fails is because a user sometimes lacks a certain attribute that a view expects it to have. For instance, most users in my application have an education (school, degree, etc.) entry in our system, but some users do not. Assuming my view looks something like this:
<% #educations.each do |education| %>
<%= education.school %>
<%= education.degree %>
<% end %>
I want to avoid "Pokemon" exception handling and feel that there has to be a better way around dealing with a "undefined method `degree' for nil:NilClass" error in the case that a user does not have an education entry in our database. This just seems like an ugly/tedious fix:
<% #educations.each do |education| %>
<% if education.school %>
<%= education.school %>
<% end %>
<% if education.degree %>
<%= education.degree %>
<% end %>
<% end %>
Any input is appreciated. Thank you!
As long as you know the first object you're working on won't be nil, the easiest way is to just do this:
- #educations.each do |education|
= education.try :school
= education.try :degree
The #try method is pretty handy. You can also call .to_s on anything you think might be nil, Ie:
- #educations.each do |education|
= education.school.to_s
= education.degree.to_s
This will convert nils to an empty string. This isn't as useful in the view IMO, but comes in handy a lot of times if you have input that is expecting to be a string and might be empty. Ie a method like:
def put_in_parenthesis(string)
"(" + string.to_s + ")"
end
You have a couple of options here.
The easiest to implement is the try method. It is used like so:
<%= education.try( :degree ) %>
The problem is that try() is viewed as a bit of an anti-pattern. As the reference indicates, you can achieve similar functionality with something like:
<%= education && education.degree %>
This isn't really a lot different, intellectually, in my opinion. A popular way of handling this a little more cleanly is the Null Object pattern, which is basically an object with defined neutral ("null") behavior.
I have created a very simple model called Discussion and one of the columns is a boolean called resolved. The idea being that once a discussion item has been resolved that value is set to true.
On the edit form, I tried to put in some logic based on the value of that field.
<%= form_for(#discussion) do |d| %>
...
<% if d.resolved == "true" %>
<p>The discussion is resolved</p>
<% else %>
<p>The discussion is not resolved</p>
<% end %>
<% end %>
However, I'm getting an error message
undefined method `resolved' for #<ActionView::Helpers::FormBuilder:0x00000101674678>
I tried adding an attr_accessor line to my model but that didn't do anything for me either. I'm not sure what I have to do to fix this. I'm pretty new to rails, so I'm sure that whatever the problem is it's probably pretty simple to fix, but I just don't get it. Thanks.
Because d represent an instance of the form builder, you want
<% if #discussion.resolved %>
If resolved is represented as a "boolean" in ActiveRecord.
every boolean column represents as predicate, so you can use:
if #discussion.resolved?
...
end
What you're looking for is the resolved? method.
<% if #discussion.resolved? %>
which is auto-generated for boolean columns.
When you set a validation message in paperclip, such as
validates_attachment_presence, :image, :message => 'xxxx'
The custom message comes automatically prefixed with the name of the field, even though it has been overwritten with the :message . How do you totally override the message and make it totally custom?
Edit: typo
Not a real solution but a Easy one is to skip paperclip validation and write custom one.
validate :check_content_type
def check_content_type
if !['image/jpeg', 'image/gif','image/png'].include?(self.image_content_type)
errors.add_to_base("Image '#{self.image_file_name}' is not a valid image type") # or errors.add
end
end
I hope it can help
You actually want to do this inside your view rather than your model and it's actually quite straight forward. We're just going to loop through the errors, and when the one for your attachment comes up we'll ignore the field name:
<ul>
<% #myObject.errors.keys.each do |field| %>
<% #myObject.errors[field].each do |msg| %>
<% if field == :image_file_name %>
<li><%= msg %></li>
<% else %>
<li><%= field.to_s + " " + msg %></li>
<% end %>
<% end %>
<% end %>
</ul>
Replacing #myObject with the name of your model that should display only the message set to your attachment validation errors. This is just a simple example that displays them inline with the rest, but of course you could do anything you like with the messages. It's important to keep the name of the field that had the error in case you want to program any logic thats specific to its failure without having to rely on the error message staying exactly the same forever.
It's standard Rails behavior to show include the attribute name before the validation errors. You have a few options to work around this behavior:
Make your error message OK to have the attribute name prepended :)
Use a different error message formatter. It's pretty easy to write your own helper to iterate through an #object.errors and wrap messages in HTML tags. I prefer to use the error messages in-line near the fields so we always skip the attribute name.
Custom validation which adds the errors to base. This is easy, but wrong, since you're suggesting there's a validation error on a field. Still may solve your problem.
Override humanized_attribute_name for that attribute to hide it. humanized_attribute_name is probably used elsewhere, so this may cause other issues.
.
HumanizedAttributesOverride = {
:image => ""
}
def self.human_attribute_name(attr)
HumanizedAttributesOverride[attr.to_sym] || super
end
I don't know if it's just a typo inside your question, but it should be:
validates_attachment_presence :image, :message => 'xxxx'
And I would not use :message to add a custom error message, but put it inside a locales file.