Customizing Model Validation error messages alerts - ruby-on-rails-3

I'm trying to customize the error message alert that users see at the top of a form when they input data incorrectly. The error message alert I'm trying to customize are for Model Attributes which are in a nested form.
I've tried the solution here which says to edit the config/locales/en.yml file but this only changes the message not the name of the model & attribute which are displayed before the error message.
I've also tried what Billy's suggested in his answer bellow which has the same result. i.e.
1 error prohibited this hikingtrail from being saved:
- Directions directions from 'My Custom Blank Error Message'
Is there a way for me to display a more user friendly Model & attribute name in my error message or remove them entirely from the error message?
Here is what I have:
config/locales/en.yml
# Sample localization file for English. Add more files in this directory for other locales.
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
activerecord:
models:
direction: "In the Getting There section"
attributes:
direction:
directions_from: "From field"
errors:
full_messages:
format: "%{message}"
models:
direction:
attributes:
directions_from:
blank: "My Custom Blank Error Message"
Model
class Direction < ActiveRecord::Base
belongs_to :hikingtrail
attr_accessible :directions_by, :directions_desc, :directions_from
validates :directions_from, :presence => {message: "'My Custom Error Message'", :if => Proc.new { |a| a.directions_by? || a.directions_desc? } }
validates :directions_by, :presence => {message: "'My Custom Error Message'", :if => Proc.new { |a| a.directions_from? || a.directions_desc? } }
validates :directions_desc, :presence => {message: "'My Custom Error Message'", :if => Proc.new { |a| a.directions_from? || a.directions_by? } }
end

You can use :message option to assign custom error message.
Example:
validates :directions_from, presence: true,
message: "'Direction from' really really really can't be blank!"
Then this custom error message will appear as <%= msg %> in the form view.
Ref: http://edgeguides.rubyonrails.org/active_record_validations.html#message
Add
To answer OP's question on the comment, i.e. the message shown in web page is not very friendly, showing result as "Directions directions from 'Direction from' really really really can't be blank"
The reason is the view template use errors.full_messages to show the error messages. You can easily customize it with two options:
Option 1: Write the custom message without subject. i.e. really can't be blank
Option 2: Write the message as before in full sentence, but refer to message only in view, instead of full_message
Example:
<% #hikingtrail.errors.messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
Ref: http://rubydoc.info/docs/rails/3.2.8/ActiveModel/Errors (full_message is nothing more but a mix of attribute and message)

With Rails 6, it's now possible to customize the format used by full_messages helper at the model or at the attribute level.
en:
activerecord:
errors:
models:
direction:
attributes:
directions_from:
format: "%{message}"
blank: "'Direction from' really really really can't be blank!"
This way the generated message for this error would be your message without the model prefix, leaving intact the default full_messages for other models and attributes.
More on that in this article :
https://blog.bigbinary.com/2019/04/22/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level.html

Related

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()

rspec vs 'url_validation' gem

I'm struggling with rspec as a new Rails person and I have a need to validate a url passed into Active Record. This is probably due to my ignorance so pls point me in the right direction. The video_url is a string field which I'd like to validate as being a valid URL. Looking around, I chose this gem because it appeared to be fully tested in rspec. For my test I didn't see how I could incorporate his validation test into my model test.
In rails console, I created a Post object and ensured that if I put a bogus URL that I knew would not be found, I would get an error. The curious thing is that attempting to replicate this in a test with the gem installed fails the test because it finds no errors. I expected an error of some kind as I got in console. My question is what am I doing wrong in that it gets no errors? I've made several attempts to triangulate what might be causing it but the gem doesn't seem to work in rspec? I would have thought that if I could get it to work in console, I can get it to work in rspec?
post.rb
class Post < ActiveRecord::Base
attr_accessible :body, :title, :image, :video_title, :video_url
validates_presence_of :title, :body, :author
validates :video_url, :presence => true, :if => :video_title_present?, :url => {
:check_path => [ 300..399, 400..499, 500..599 ], :allow_nil => true,
:url_not_accessible_message => "must be valid.",
:invalid_url_message => "must be valid.",
:url_invalid_response_message => "must be valid."}
def video_title_present?
!self.video_title.blank?
end
belongs_to :author, class_name: "User"
end
post_spec.rb
before do
#post = Post.new(title: "foo", body: "my body here")
end
describe "validates with video links" do
it "validates with video url and video title" do
#post.video_url = "http://heckitoqi.com"
#post.video_title = "my title"
#post.should have_at_least(1).error_on(:video_url)
end
end
Output in console:
Failure/Error: #post.should have_at_least(1).error_on(:video_url)
expected at least 1 error on :video_url, got 0
In some of my errors, I attempted a more open-ended error, but it fails by not catching any errors.
Here is a short version of my smoke test of the model using Rails console:
u = User.first
p = Post.new(title: "title", body: "body", video_title: "vtitle", video_url: "http://heckitoqi.com")
p.author = u
p.save!
>> HTTPI GET request to heckitoqi.com (net_http)
>> ActiveRecord::RecordInvalid: Validation failed: Video url must be valid.
If I can get it to validate in the console, then my implementation of the test is at fault, right? I just don't see what I'm doing wrong. thanx, sam

Unable to find field "Name" (Capybara::ElementNotFound)

I'm trying to use capybara+rspec and get this error: Unable to find field "Name" (Capybara::ElementNotFound)
Here is my form:
%h2 Sign up
= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-vertical' }) do |f|
= f.error_notification
= display_base_errors resource
= f.input :name, :autofocus => true
= f.button :submit, 'Sign up', :class => 'btn-primary'
= render "devise/shared/links"
Here is my user_steps.rb
When /^I sign up with valid user data$/ do
create_visitor
sign_up
end
def create_visitor
#visitor ||= { :name => "Test visitor"}
end
def sign_up
visit '/users/sign_up'
fill_in "Name", :with => #visitor[:name]
click_button "Sign up"
end
What's wrong????
I encountered this issue and realized that Capybara filtered out hidden fields--my element belonged to a non-active tab (hidden) in a multi-tab page. I just passed the :visible arg and set it to false, and voila! the element was found.
fill_in "content", with: 'foo bar', visible: false
or
find('#item_content', visible: false).set 'foo bar'
It looks like to me that you are looking for a field label Name, but your name field does not have a label, so you probably need to use the ID of the field or the name which is probably:
"#{resource_name}[name]"
Also, as #nmott said in his comment, you should try using save_and_open_page so that you can actually look at the page, However, be aware you need the launchy gem to use this method.
Furthermore, what you might discover is you're not even on the right page. My usual problem when testing pages OTHER than the sign up page is that I've been redirected and didn't know it. So after using visit, you should also use assert_template to make sure you're on the right page.
I have the same problem myself and I had to stop using fill_in all together.
What I did was replacing all occurrences of fill_in with the following code :
element = page.find("Name")
element.set(#visitor[:name])
I guess you can encapsulate this into a method in order to make your tests more smooth
Try to narrow down your scope from within the form as such
within("form#whatever_form_id") do
fill_in "Name", :with => #visitor[:name]
click_button "Sign up"
end
Ok guys I found it out having the same issue , its very simple :
In capybara or rspec they need you to but "Name" and in your form or label field you need to write "name" in small....there you go works for me.
For me it was the next line of the spec that was causing the problem not the fill_in "name" line. It didn't matter whether or not name was "Name" or "name".
The next click_button line for me had click_button "Wrong Name" which was the wrong name for the button, and this did not give the expected error of "can't click on button "Wrong Name" but instead gave can't find field "name".
A bit verbose for my first even post on stack overflow. Bottom line. Consider the line below the line given in the capybara error message.

File Handling with Paperclip

I'm using Paperclip in a gem I built for a specific use case. My gem creates an interface for non-programmers to create and edit forms and then allows users to answer those forms.
I want to use Paperclip in order to provide a "File Upload" input type for questions, so my forms are more versatile. However, this means that I need to use the file_field_tag method to display the file input and I need to manually save whatever information is submitted through that input into the appropriate model object. Currently I'm sending the information through with the name question_1 and then trying to pull the uploaded data out with params["question_1"].
My code looks like this:
answer.update_attributes(upload: params["question_1"])
But I'm getting a No handler found for <image_name> error and I can't figure out what I'm doing wrong. I thought Paperclip handles everything after I pass it the data from a file_field?
Solution:
My form looked like this: <%= form_for #answer_set, multipart: true do %> when it should have looked like this: <%= form_for #answer_set, html: { multipart: true } do %>.
I use
has_attached_file :image
validates_attachment_presence :image
validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/png', 'image/jpg', 'image/pjeg']
and then:
#upload = Upload.find(params[:id])
#upload.update_attributes(params[:upload])
config/environment.rb
Rails::Initializer.run do |config|
config.gem "paperclip", version: "~> 2.7"
end
This thread also suggests checking the multi-part on the form
https://stackoverflow.com/a/10076046/1354978
answer_form_for #upload, :html => {:multipart => true} do |f|
There are also other possible solutions on that page.

expected Hash (got Array) for param 'samples'

I have been following Railscasts episodes of Nested forms and complex forms. During the time of creating multiple model in a single form I was able to edit, update, delete and create records for sample models that were nested in the Batch model.
I have been breaking my head from a long time and tried searching around as well but could not get any right solution for solving this problem.
my development log file gives me the following error.
ERROR MESSAGE:
Status: 500 Internal Server Error
expected Hash (got Array) for param `samples'
in my controller I have the update action like this
def update
#batch = Batch.find(params[:id])
respond_to do |format|
if #batch.update_attributes(params[:batch])
flash[:notice] = 'Successfully updated Batch.'
format.html { redirect_to(#batch) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #batch.errors, :status => :unprocessable_entity }
end
end
end
my view is something like this:
<%= form_for #batch do |f| %>
......
<%= f.fields_for :samples do |s_form| %>
.... s_form things
<% end %>
<% end %>
my model contains the same stuff :
has_many :samples, :dependent => :destroy
accepts_nested_attributes_for :samples, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
All suggestions are appreciated.
for others who met the same problem:
this error is caused when you have two fields in your form like:
video: 'some string'
video['url']: 'some url'
then rails will crash with the error: expected Hash (got String) for param
the solution is quite simple: change 'video' to something else. e.g.:
video_origin_url: 'some string'
video['url']: 'some url'
I had the same problem, and just fixed it.
Check the headers of your request. I mine I saw:
weight[2][name]:Tests
weight[2][value]:75
weight[1][name]:Quizzes
weight[1][value]:25
weight[][name]:Foo
weight[][value]:
It was the last two which caused the issue. In my case I had to give this weight an ID to get rid of the error.
I also got this error Invalid request parameters: expected Hash (got Array) for param 'cell'.
In my case, I misformed the field name like
f.text_field :name, name: 'cell[name][]'
this was causing the error. Now I did the following and the error is gone:-
f.text_field :name, name: 'cell[][name]'
in this solution I was actually trying to get data in array format.
I had this problem, when the user typed the params himself in the request like:
https://example.com/page?samples[]=1&samples[test]=2
Debugging the code, I got down to a Rack::QueryParser.parse_nested_query method in the rack gem:
# parse_nested_query expands a query string into structural types. Supported
# types are Arrays, Hashes and basic value types. It is possible to supply
# query strings with parameters of conflicting types, in this case a
# ParameterTypeError is raised. Users are encouraged to return a 400 in this
# case.
def parse_nested_query(qs, d = nil)
params = make_params
unless qs.nil? || qs.empty?
(qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
k, v = p.split('=', 2).map! { |s| unescape(s) }
normalize_params(params, k, v, param_depth_limit)
end
end
return params.to_h
rescue ArgumentError => e
raise InvalidParameterError, e.message, e.backtrace
end
From the docstring:
It is possible to supply query strings with parameters of conflicting types, in this case a ParameterTypeError is raised. Users are encouraged to return a 400 in this case.
I found few solutions here Rails ActionController::BadRequest causes 500 Server Error on production server