How do you customize Ruby on Rails validation errors? - ruby-on-rails

Currently when there is a validation error, a div with class="field_with_errors" gets rendered in my form:
<form method="post" action="/users" accept-charset="UTF-8">
<div class="field_with_errors">
<input id="user_email" type="text" value="tom#test.com" name="user[email]">
</div>
<input id="user_password" type="password" value="mypass" size="30" name="user[password]">
<input id="user_submit" type="submit" value="Submit" name="commit">
</form>
Without the use of an additional gem and in a Rails 3 environment, is there a way to modify how the validation error is rendered? For example, I want the validation error div to be rendered after the input tag with the error:
<input id="user_email" type="text" value="tom#test.com" name="user[email]"><div class="field_with_errors"></div>
Also, is there a way to render a specific error? If it was an email error, then render the div after the input textbox and produce a "Re-enter your email" message.
(Most of the searches I have done so far use gems as the solution.)

1.You can remove the field_with_errors wrapper by overriding ActionView::Base.field_error_proc.It can be done by putting this in your config/application.rb:
config.action_view.field_error_proc = Proc.new { |html_tag, instance| "#{html_tag}".html_safe }
Refer
Rails 3: "field-with-errors" wrapper changes the page appearance. How to avoid this?
2.You can display error message on specific field.
<input id="user_email" type="text" value="tom#test.com" name="user[email]">
<% if #user.errors.on(:email).present? %>
<span class="error">Re-enter your email(or)<%= #user.errors.on(:email) %></span>
<% end %>
Then in your CSS
.error {
color: red;
}

Related

Capybara can't find selector on page

I'm trying to test the presence of some form fields in the bootstrap navbar and can't find the right combination of Capybara selectors to find them.
I've tried the following options in Capybara:
should have_selector('id', text: 'email')
should have_selector('name', text: 'email')
should have_selector('div.input.id', text: 'email')
should have_selector('div.input.placeholder', text: 'email')
and I always get the error:
Failure/Error: expect (should have_selector('div.input.placeholder', text: 'email'))
expected to find visible css "div.input.placeholder" with text "email" but there were no matches
I'm fairly new to capybara, which is probably my problem, but I've looked through the documentation and this seems like it should work.
I'm guessing this has something to do with it being hidden, but it is visible to a user when you go to the page, so I'm not sure how to get it to be visible to capybara.
Here is the HTML code that is being presented:
<div class="navbar-collapse collapse">
<form class="navbar-form navbar-right" role="form" action="/sessions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="klUhJ9epE/Sr/N0okPq5WMWi2XJuQXiAPmdg/9Qf2d8TBX+htbIdUPRh01YPWqMTRin8vTlVG/ECUtvKNczc+A==" />
<div class="form-group">
<input type="text" name="email" id="email" class="form-control" placeholder="Email" />
</div>
<div class="form-group">
<input type="password" name="password" id="password" class="form-control" placeholder="Password" />
</div>
<input type="submit" name="commit" value="Sign in" class="btn btn-primary" />
</form>
</div><!--/.navbar-collapse -->
Here is the view of the actual page:
div.input.placeholder is a CSS selector that would select a div element with the classes 'input' and 'placeholder' - I'm assuming that's not what you're actually trying to check for.
If you are trying to test the attribute values you would do
have_selector('input[id="email"][placeholder="Email"]')
or better yet since you're using CSS
have_css('input[id="email"][placeholder="Email"]')
or you could use Capybaras built-in :field selector type and do
have_field(id: 'email', placeholder: 'Email')
Realistically though - checking attributes like this is overkill for a feature test. Just fill in the fields
fill_in('Email', with: 'my_email#blah.com')
which will confirm the relevant field exists, can be located by label or placeholder of the string 'Email' and can be filled in.

Submit button does not submit form data in bootstrap

I am trying to submit a form in a bootstrap framework and cannot get past the validation, even with correct data.
I think there might be an error with this syntax,
<form name=form1 method=post action=signupck.php onsubmit='return validate(this)'><input type=hidden name=todo value=post>
then the form fields... which all display correctly - so no problems there - in the style:
<div class="row">
<div class="col-xs-2">
<label for="fname">Forename</label>
<input type="text" class="form-control" id="fname" placeholder="Forename"><br></br>
</div>
<div class="col-xs-2">
<label for="sname">Surname</label>
<input type="text" class="form-control" id="sname" placeholder="Surname">
</div>
</div>
and then,
<input type=submit value=Signup>
<input type="reset" class="btn btn-default" value="Reset">
The form on submission displays signupck.php, signalling validation messages when is should be submitted ok. I have got this working outside the bootstrap, but when I put this inside the template, in the form above, I get the problems.
Any help would be most appreciated.

Acts-as-Taggable in Rails 4 won't work properly

I am using the acts-as-taggable gem in a Rails 4 app with an angular frontend. If I use the console it works fine. I have done all the obvious things and I can get it to work by adding this to the create controller:
if params[:tag_list]
droplet.tag_list.add(params[:tag_list], parse: true)
end
The problem is that it should be doing this anyway. Does anyone have any insight as to why it is simply not firing the tag_list.add method automatically? I am uncomfortable using this hack to get it to work.
And yes, I have added :tag_list to the strong parameters.
Update: The form html
<form ng-submit="createNewDropletForm.$valid && createNewDroplet()" name="createNewDropletForm" novalidate>
<div class="form-group">
<label for="name">Title:</label>
<input ng-keyup="keyup()" ng-model="drop.name" ng-model-options="{ debounce: 500 }" type="text" class="form-control" placeholder="Add Droplet Title Here" required>
</div>
<div class="form-group">
<label for="description">Description:</label>
<textarea class="form-control" rows="4" ng-model="drop.description" placeholder="Add helpful description of what this droplet tests." required></textarea>
</div>
<div class="form-group">
<label for="tags">Tags:</label>
<input class="form-control" ng-model="drop.tag_list" placeholder="add tags separated by commas">
</div>
<button type="submit" class="btn btn-default">Next</button>
</form>

Using Capybara how would I would I overwrite an existing field value?

I am currently testing a form on a page with Capybara that has existing values filled out in the form's fields. I want to test being able to put new values into the fields and submitting the form with the new values.
When I try using Capybara's fill_in method it ignores the fields that have existing values. Is there anyway to overwrite fields with existing values in Capybara?
I'll include the form below:
<form accept-charset="UTF-8" action="/submissions/1/reviews/4" class=
"simple_form edit_review" id="edit_review_4" method="post" novalidate="novalidate"
name="edit_review_4">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓"><input name="_method" type=
"hidden" value="put"><input name="authenticity_token" type="hidden" value=
"gJ/KKAodeIJD8PPnRNeN4GaGb/yqvUDHrsnl9LqLP/c=">
</div>
<div class="input integer optional">
<label class="integer optional control-label" for=
"review_rating">Rating</label><input class="numeric integer optional" id=
"review_rating" name="review[rating]" step="1" type="number" value="33">
</div>
<div class="input text required">
<label class="text required control-label" for="review_comment"><abbr title=
"required">*</abbr> Comment</label>
<textarea class="text required" cols="40" id="review_comment" name=
"review[comment]" rows="20">
hellofsdf
</textarea>
</div><input class="btn" name="commit" type="submit" value="Update Review">
</form>
The Capybara code I've tried is:
find(:xpath, "//*[(#id = 'review_comment')]").set "hello"
I've also tried a similar approach with the rating field since the rating is a text field and the comment is a text area, but I still can't get it to change.
using find with XSLT expression should do the trick
find(:xpath, "//input[#id='field_with_default_value_id']").set "my value"
Use a javascript driver like phantomjs/poltergeist and then use javascript to set values like that.
page.evaluate_script("document.getElementById('#some-id').value = 'some-value'");
Similar to my answer on this question.

error (div class="fieldWithErrors") workaround?

In my project, I have a register form.
My HTML looks like
<form method="post" action="/users">
<div style="margin: 0pt; padding: 0pt;">
<input type="hidden" value="lDHrKRC2ENhRKcaoBR4XGfzri/MY09PjqVDvHRtC0D4=" name="authenticity_token"/>
</div>
<p><label for="login">Login</label>
<input type="text" size="30" name="user[login]" id="user_login"/></p>
<p><label for="email">Email</label>
<input type="text" size="30" name="user[email]" id="user_email"/></p>
<p><label for="password">Password</label>
<input type="password" size="30" name="user[password]" id="user_password"/></p>
<p><label for="password_confirmation">Confirm Password</label>
<input type="password" size="30" name="user[password_confirmation]" id="user_password_confirmation"/></p>
<p><input type="submit" value="Sign up" name="commit"/></p>
</form>
Now generating an error by submitting an the empty form my code looks like:
<form method="post" action="/users">
<div style="margin: 0pt; padding: 0pt;"><input type="hidden" value="lDHrKRC2ENhRKcaoBR4XGfzri/MY09PjqVDvHRtC0D4=" name="authenticity_token"/>
</div>
<p><label for="login">Login</label>
</p><div class="fieldWithErrors"><input type="text" value="hg" size="30" name="user[login]" id="user_login"/></div>
<p><label for="email">Email</label>
</p><div class="fieldWithErrors"><input type="text" value="gh" size="30" name="user[email]" id="user_email"/></div>
<p><label for="password">Password</label>
</p><div class="fieldWithErrors"><input type="password" value="gh" size="30" name="user[password]" id="user_password"/></div>
<p><label for="password_confirmation">Confirm Password</label>
<input type="password" value="gh" size="30" name="user[password_confirmation]" id="user_password_confirmation"/></p>
<p><input type="submit" value="Sign up" name="commit"/></p>
</form>
this will destroy my layout.
Is there a solution doing
<input type="text" value="gh" size="30" name="user[email]" class="fieldWithErrors" id="user_email"/>
instead of
<div class="fieldWithErrors"><input type="text" value="gh" size="30" name="user[email]" id="user_email"/></div>
?
Create a new initializer, for example, /config/initializers/field_error.rb:
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance_tag|
if html_tag =~ /<(input|textarea|select)[^>]+class=/
class_attribute = html_tag =~ /class=['"]/
html_tag.insert(class_attribute + 7, "fieldWithErrors ")
elsif html_tag =~ /<(input|textarea|select)/
first_whitespace = html_tag =~ /\s/
html_tag[first_whitespace] = " class='fieldWithErrors' "
end
html_tag
end
Ryan Bates covered this in Railscast episode 39
This is an error in how Rails shows form errors. This is an old and known issue with Rails: https://rails.lighthouseapp.com/projects/8994/tickets/1626-fieldwitherrors-shouldnt-use-a-div
Why it still hasn't been solved is a mystery to me. I guess it's one of those many little things that you need to override manually in Rails. Definitely try John Topley's workaround, though. Or fix it in your local Rails code and submit that as patch to Rails.
Maybe you should consider using formtastic http://github.com/justinfrench/formtastic.
The Railscast is the way to go but you need to update it for Rails 3.x.
add this to the end of your environment.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance_tag|
"<span class='field_error'>#{html_tag}</span>".html_safe
end
Bounce the rails application and you'll be set.

Resources