How do you edit Devise error messages? - ruby-on-rails-3

To be clear, I know how to edit the error messages in config/locales/devise.en.yml but I'm referring to styling these type of error messages:
2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
--
All i see is <%= devise_error_messages! %> on the sign-up page, but I don't know how to actually edit the error messages themselves.
In my case the messages appear on the left, and my sign up is centred (which looks odd), I also don't like the red color of the messages and would prefer a different color.
So my question is, how can I style the error message? centre it, and change the color.
Not sure which other controllers or contents to include so as soon as you ask, i'll update the OP with them if need be.

See the sources for the devise_error_messages! method at https://github.com/plataformatec/devise/blob/master/app/helpers/devise_helper.rb.
All the errors are inside
<div id="error_explanation">
so you can use that fact in your CSS. Inside it uses only basic styling: h2 for the header message, ul for the individual errors. See this SO example for #errorExplanation styling, for example: how to beautify validations in rails. Just don't forget to replace #errorExplanation with #error_explanation in the example.
But your best approach would probably still be to rewrite this method or write and use your own, and there apply all the styling you like.
I'd personally recommend displaying errors next to the fields they belong to. See this SO thread, for example, on how to do that: Rails: Errors close to particular fields in forms.
Another improvement would be switching to simple_form for your forms (and getting errors-next-to-fields for free). See, for example, an excellent Railscast on that: http://railscasts.com/episodes/234-simple-form. There's a more recent revised Railscast, but not sure if you're a Pro subscriber there.

Related

Redmine: Copy issue multiple times

Copying one issue and its child issues is a natively built-in feature and thus works just fine.
But is there a way to do this multiple times?
Like re-creating one issue (including its children) twenty or fifty times?
Edit 2
This new functionality should be accessible via the Redmine interface and compatible to any browser.
It does not matter whether it is a completely new Plugin, an extension to the built-in copy feature, a call to a PHP-script or anything else.
Due to compatibility (networking, browsers etc.) I guess a completely server-side modification is the only way to go here.
What parts of the default plugin (as created in the voting tutorial) or a core element would have to be changed?
Where can I find the code for the native issue copy function?
Or - if all this is too complicated - how would I write my plugin to point to a PHP file that manipulates the SQL database directly?
Edit:
To clarify: just like the normal copy function (either in the context menu or the top-right link, I don't care) I want to copy one issue and its sub-issues n times.
To let the user set the amount n, any user number input may suffice, like a textbox, a pop-up etc.
I think the simplest way to do this is to start with redmine source modification.
Once it works you can move on and try to extract this feature into plugin.
Note, that I am not a ruby developer, so some things below are just my guesses. But I did few small redmine modifications like this before and hope that my thoughts can be useful.
It will also be easier if you familiar with some of MVC frameworks (for any language), because they mostly have a similar structure with routes, controllers, views and models.
The Idea
The link to copy single issue looks like this: //redmine.myserver.com/projects/myapp/issues/12407/copy.
My idea is to add a num_copies parameter to this link and use it in the code to create many copies.
You need no UI for that, once implemented the feature will work like this:
find the issue you need
choose the copy action for it
once the form opened, manually add ?num_copies=XX parameter into the URL (//redmine.myserver.com/projects/myapp/issues/12407/copy?num_copies=50) and press 'Enter' to reload the form
check the details and submit the form - it will create multiple copies according to the num_copies parameter
The Implementation Plan
Now, how to do this.
I am referring to the redmine mirror on github which looks fresh.
1) Find where the .../copy link is handled
When you open the form to copy the issue, you'll see form like this:
<form action="/projects/myapp/issues" class="new_issue" id="issue-form" method="post">
<input id="copy_from" name="copy_from" type="hidden" value="12407">
<div class="box tabular">
<div id="all_attributes">
...
</form>
Note the form action, it points to the /issues link and it will submit the copy_from parameter (this is ID of the issue we are copying).
2) Find the code which handles the form submission
We could first go and check through the config/routes.rb, but we can just guess that we need the controllers/issues_controller.rb
Search for the place where copy_from parameter is used.
You'll see the build_new_issue_from_params method.
Now search for its usages and you'll find this:
before_filter :build_new_issue_from_params, :only => [:new, :create]
From how it looks, I guess that it is called before both new and create actions.
Looking at new and create definitions, the new action renders the new issue form and the create action handles the form post.
3) Add the num_copies parameter to the form
Find the view file used by new issue action.
Here there is a template for the new issue form, try to add num_copies parameter similar to the copy_from:
<%= title l(:label_issue_new) %>
<%= call_hook(:view_issues_new_top, {:issue => #issue}) %>
...
<%= error_messages_for 'issue' %>
<%= hidden_field_tag 'copy_from', params[:copy_from] if params[:copy_from] %>
Here I am not 100% sure if it will just work if you add a similar line for `num_copies. You may also need to modify the route.
When done, you should have the new issue form like this:
<form action="/projects/myapp/issues" class="new_issue" id="issue-form" method="post">
<input id="copy_from" name="copy_from" type="hidden" value="12407">
<input id="copy_from" name="num_copies" type="hidden" value="50">
<div class="box tabular">
<div id="all_attributes">
...
</form>
4) Handle the num_copies parameter
It should be done in the create action:
def create
...
call_hook(:controller_issues_new_before_save, { :params => params, :issue => #issue })
#issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
if #issue.save
...
end
Here you already have the #issue variable created in the build_new_issue_from_params method and what you need to do is to check if num_copies parameter is set and if it is set then copy / save the #issue in a loop to create additional copies.
I can't provide the exact code snippet for this, but it should not be very complex.
Check this code in the bulk_update method, it looks like what you need:
issue = orig_issue.copy({},
:attachments => copy_attachments,
:subtasks => copy_subtasks,
:link => link_copy?(params[:link_copy])
)
I think this specific plugin is not high priority for Redmine community.
But, you can write very easy API calling for Java, Python or other language to do what you exactly want.
Here, you can see API documentation how to list, create, update issues.
Issue API documentation
PS: You can leave your request in redmine community,
maybe you are lucky https://redmine.org/projects/redmine/issues

Recaptcha ambethia - Input error: k: Format of site key was invalid / invalid-request-cookie

The error in the title is visible only in firebug. Everything from where I put the recaptcha element on down, is not shown on the page, though is present in the page-source (Mozilla and Opera) - though no error is shown in firebug.
So far, based on others solutions, I have tried reversing the keys (public and private, though they are clearly identified), generating a global-key-pair and using those, and even hard-coding the values into the recaptcha.rb initializer file versus using system-vars. No luck in any cases in dev or production. Also tried suppressing the 'noscript' part, with no change.
The Gem-Generated Page Source reads:
<script type="text/javascript" src="//www.google.com/recaptcha/api/challenge?k=[" mypublickeyhere", "myprivatekeyhere", false]&lang="></script>
<noscript>
<iframe src="//www.google.com/recaptcha/api/noscript?k=["mypublickeyhere", "myprivatekeyhere", false]" height="300" width="500" style="border:none;"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/></noscript>
Why is my private key visible in the page-source? All that code comes from putting this in my view:
<%= recaptcha_tags %>
Edit: Made some progress, many hours in, by force-feeding the keys in the form and controller with:
<%= recaptcha_tags :public_key => 'mypublickeyhere' %>
and
if ( verify_recaptcha :private_key => 'myprivatekeyhere' )
Which gets the recaptcha to show up on the form, and keeps my private-key from being spammed to the page-code by the plugin as it does in 'default' mode.
Unfortunately, even if captcha is entered correctly, we get a NEW Error, "invalid-request-cookie".
Is there a single example of using this plugin in Rails 3, with full working form and controller code?
More Info for other sufferers:
Google Says this error means: "The challenge parameter of the verify script was incorrect."
On another page, if you search for "challenge parameter," to find out whatever that is, Google says: "recaptcha_challenge_field is a hidden field that describes the CAPTCHA which the user is solving. It corresponds to the 'challenge' parameter required by the reCAPTCHA verification API."
So why is the plugin not providing the correct challenge parameter as it should? Perhaps I need to pass something somewhere - but what and where? Again, a simple example would be great.
0.0. Setting the Variables - an aside:
Use ENV['key'] to keep your keys out of the codebase (though you can hardcode them in /config/environments/development.rb and then not include this file on your production server (for Heroku, add to gitignore in your push folder).
I added this to my development.rb file
# Set variables for Recaptcha on Localhost
ENV['RECAPTCHA_PUBLIC_KEY'] = 'mypublickeyhere'
ENV['RECAPTCHA_PRIVATE_KEY'] = 'myprivatekeyhere'
You will put your real key values in place of mybpublickeyhere and myprivatekeyhere.
You could also set ENV variables on your dev-machine. I prefer not to add that clutter, as this machine is used to develop many sites at once.
If deploying to Heroku, learn how to set these ENV variables here:
http://devcenter.heroku.com/articles/config-vars
1.0 Get a set of global-keys, not tied to any particular domain, and use these for testing. After eliminating that potential problem, when all is working, put in your domain-specific keys, on your production machine, and re-test.
2.0 Don't use the 'default' method. From what I can tell, it simply does not work - maybe it once did and Google changed something - I don't know, but it may/will give you the dreaded "Input error: k: Format of site key was invalid" AND will reveal your private key to anyone who views the page-source.
The solution is to force-feed the keys into the form and controller. So, in your form this will look like:
<%= recaptcha_tags :public_key => ENV['RECAPTCHA_PUBLIC_KEY'] %>
3.0 In your controller you will test for true; but again, force-feed the private key like this:
if ( verify_recaptcha :private_key => ENV['RECAPTCHA_PRIVATE_KEY'] )
... your success code here
else
... your fail code here
end
4.0 Placement of the tag in the form is important. The Devise docs refer to this gem, and provide actual example code of using this gem:
http://github.com/plataformatec/devise/wiki/How-To:-Use-Recaptcha-with-Devise
They say to put the recaptcha_tags immediately above the submit button code. This is important. I had to put it within:
<div class="form-actions">
... along with the button
Other sources report that surrounding HTML can break things in mysterious ways, so you may have to experiment for awhile (hope you don't have deadlines, or anything). These 'placement' issues were the culprit with the 'invalid-request-cookie' error I received.
I hope these guidelines shorten your development time.

Model paper clips validations errors are not displayed in simple_form

I am using paper_clip and simple_form gems. Unfortunately, it seems that paper clip validations errors are not displayed in my form.
I have try several types and syntax of paper_clip content_type validations and even they work (the uploaded files types are restricted) no error is displayed in the form.
Has anyone knew know how to fix this?
Here's what I suspect - the paperclip validation is likely being made on an attribute that's not actually an input in simple_form.
You might have something like this in your form:
<%= f.input :picture, :label => "Picture" %>
But paperclip's validation errors aren't going to be put on 'picture' - they'll be put on another attribute, like 'picture_file_name'. Since simple_form has a 'picture' input, and not a 'picture_file_name' input, it doesn't know where to put the errors, so they don't show up.
Take a look at your errors array and confirm what attribute's getting the errors. Then use simple_form's errors helper in your view to put that attribute's error in the appropriate place:
<%= f.error :picture_file_name %>
Unfortunately paperclip provides own format for validation errors storing them in 3 different attributes without linking to base model attribute:
*_file_name, *_file_size, *_content_type
Therefore simple_form or any other form view helper could not map paperclip validation errors with field name.
You can patch paperclip like described here http://dev.mensfeld.pl/2013/05/paperclip-bootstrap-and-simpleform-working-together-on-rails/ and forget about this issue forever

Button being used as a link

Im maintaining a site I didnt build thats for car insurance. In the banner of every page is an input that takes you to a page with a form to fill out. I cant understand why an input is used instead of a link, is there ever a valid and semantic reason for doing this?
Occasionally, people have done this because they want a link that "looks like a button". However, it is bad design.
It was never a good idea, but in the old days there was at least some justification for it: it gave a button feel and functionality to the link. However, with modern web design there is no need to do this: the same functionality can be created simply by styling a normal link appropriately.
On the other hand, this is probably more of a style issue than a real problem. It may not be worth changing it if you are maintaining an existing site.
using button or input type="button" is the original way to set up an Ajax request. that said, since it's taking the user to another page, sounds like they do not know what they are doing and/or wanted the styles that #dan1111 mentioned

Use JS to change <form> from remote to non-remote in Rails 3, HAML

The problem is that i have a remote form that, based on condition, id like to convert to a non-remote form (using UJS), and then submit.
note the form has a file upload.
Here's the details: I have initially rendered the remote form using
= form_for #myobj, :url => {:action=>"remoteAction", :controller=>"myobjects"}, :remote => true do |f|
... (f.fields....)
which produces the HTML:
<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" data-remote="true" action="/remoteAction">
when i click submit, as expected, the form is submitted 'AS JS'.
in the controller action, i am doing some validation of the fields inside the submitted form.
If all the validations pass, i execute the following .js.haml template:
$('form#new_myobj').removeAttr("data-remote");
$('form#new_myobj').attr('enctype', 'multipart/form-data');
$('form#new_myobj').attr('action', '/myobjects/regularAction');
which successfully changes the HTML on the page (witnessed via Firebug) to:
<form id="new_myobj" class="new_myobj" method="post" accept-charset="UTF-8" enctype="multipart/form-data" action="/myobjects/regularAction">
since the form contains an f.file_field, i have to submit as multipart so the image can be uploaded, and i cannot submit 'AS JS'
now, when i click submit, the controller action 'regularAction' is indeed called, but its still 'AS JS'
the question is, what else do i need to change in the HTML so the form can be submitted non-xhr? is it related to the headers?
jQuery is a bit tricky with the data attributes since it both
reads the HTML5 data tags as well as its own storage bound to the
DOM element, that is also called data. When writing to an attribute
that value gets copied into jQuerys own data storage (presumably
when data("remote") is being called).
However, this only happens
if jQuery’s data is empty for that name. Thus setting the attribute will only work once, after that the "cached" value is being used
even if the attribute changes. In order to really get rid of the
value, we need to remove the attribute and jQuerys own storage
method in that order. The reason is that there’s a high-level
(element.removeData(…)) function and a low level one (jQuery.
removeData(element, …)). The former re-reads the HTML5 data
attribute and stores it in jQuery’s own storage. Using the rather
unusual low level function obviously works as well.
Also, we do really need to remove the attribute -- setting it to
false is not enough since Rails only checks if form.data('remote')
is not undefined (look for it in jquery_ujs.js).
TL;DR:
attr("data-remote") != data("remote")
These two lines make a form non-remote (again). Order matters.
$("form").removeAttr("data-remote");
$("form").removeData("remote");
It’s documented, if you actually know what you’re looking for:
http://api.jquery.com/jQuery.data/ (low level function)
http://blog.madebydna.com/all/code/2011/12/05/ajax-in-rails-3.html
StackOverflow doesn’t allow me to post more than two links, but you can guess the removeData one. The high-level functions are linked from the low level ones.
Avoiding the token authenticity error in Rails 4+:
As Stan commented below, just doing the above will fail with an InvalidAuthenticityToken error. The workaround is easy though, see here for details: https://stackoverflow.com/a/19858504/1684530
The problem is that your approach to disable the Ajax submission isn't quite correct. You need to unbind the JavaScript events that have already been added by rails.js (Rails UJS adapter) to the form.
You can do that by:
$('form#new_myobj').unbind() to unbind all events attached to the form. You also need to $('form#new_myobj').removeAttr('data-remote') and $('form#new_myobj').removeAttr('data-type') to remove data-remote and data-type attributes (if existent).