display error messages without brackets in rails api - ruby-on-rails-5

render( json: UserSerializer.response_error(current_user.errors.messages).to_json)
user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :email
def self.response_error(error)
error
end
end
It gives the response as below:
[
"Password can't be blank"
]
But I need to display
"Password can't be blank"
I tried to use "full_messages" but the result was same

def self.response_error(error)
error.join(', ')
end
You could do it like this. The issue is it needs to be an array. Since there could be multiple errors like.
[
"Email can't be blank",
"Password can't be blank"
]
This will be result with the above code in:
"Email can't be blank, Password can't be blank"
In general an array is easier to work with in the frontend regardless of one or many errors.
When you are absolutely sure there will only this one error you could also do
error.join('') to just get the string.

Related

Customizing Model Validation error messages alerts

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

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.

rspec shoulda syntax for model.errors

I get the following error message for the code below:
Failure/Error: #league.errors.on(:short_name).should_equal "can't be blank"
NoMethodError:
undefined method `on' for #<ActiveModel::Errors:0x000001017853f0>
#league.errors.on(:short_name).should_equal "can't be blank"
According to several documentation references that I am reading, this should work. Any idea what's going on?
Since #location.errors is a hash:
require 'rspec'
describe "Location" do
before(:each) do
#location = double("Location")
#location.stub(:errors).and_return(:short_name => "can't be blank")
end
it "should work like a hash" do
#location.errors[:short_name].should == "can't be blank"
end
end

I am having trouble testing my controller's update action using Rspec, what am I doing wrong?

I am trying to test the failing branch of the update action on my controller but I am having trouble with the test. This is what I have and it fails on the last
describe "PUT 'article/:id'" do
.
.
.
describe "with invalid params" do
it "should find the article and return the object" do
Article.stub(:find).with("1").and_return(#article)
end
it "should update the article with new attributes" do
Article.stub(:update_attributes).and_return(false)
end
it "should render the edit form" do
response.should render_template("edit")
end
end
end
Any ideas as to why the last part fails to render the template?
You're splitting up the parts of your test incorrectly. Each it call is actually a new example and the state is reset before/after each one.
What you should be doing is:
describe "with invalid params" do
before do
#article = Article.create(valid_params_go_here)
end
it "should find the article and return the object" do
put :update, { :id => #article.id, :article => { :title => "" } }
response.should render_template("edit")
end
end
By doing it this way, the #article is set up before hand (although you could use a mock one if you really wanted to) and the request to the update action and the assertion that it actually renders the edit template all happen in the one example.
For people who are coming here in 2018, some updates(pun not intended) have been made. It's important to include "params" before listing the params. Additionally, you should use expect and not "should" since it will be deprecated in Rails 6.0.
describe "with invalid params" do
before(:each) do
#article = Article.create(valid_params_go_here)
end
describe "PATCH update/:id" do
it "should find the article and return the object" do
put :update, params: { id: #article.id, article: { title: "" } }
expect(response).to be_redirect
end
end