Let's say I have a simple form in the administration of my Rails 2.x powered website.
<form action="/products/123">
Price:
<input type="text" name="product[price]" value="12.99"></input>
Description:
<textarea name="product[description]">
A long and descriptive block of text goes here.
</textarea>
<input type="submit"></input>
</form>
Admin Sally wants to change the description.
Admin Sally opens the page with this form and begins writing some new sales copy in the textarea.
A few seconds later, admin Joe decides this product needs to go on sale
Admin Joe opens the page with the form on it
Admin Joe lowers the price to $9.99
Admin Joe submits the form, setting the price in the database to $9.99
Admin Sally is done writing the copy and submits the form, but the price field in her browser still says $12.99.
Joe becomes angry and yells at Sally for changing the price back, even though she had no idea she just did that.
So the database is updated to contain what Sally had in the form, removing the price that Joe set while she was working with that page open.
Surely I am not the first one to stumble on a problem like this, but I've never had to deal with it. So first of all, does this sort of problem have a name? And second, what are some solutions to making it suck less?
A few solutions that come to mind, but some have serious drawbacks.
Don't save the record if the updated_at timestamp was changed from when you opened the form. But what happens to the content you wanted to save? You'd have to copy the content you wanted to change out of the form, reload the edit form, and then paste it back in, hoping noone else edits anything in the meantime.
Forms load with most fields disabled, requiring the admin to "unlock" the fields they want to edit, and only the unlocked fields get sent to the server on submit. This greatly reduces the likelihood of conflicts in large forms, but adds a bunch of clicks to the content editing process, even it would be fine 99% of the time.
JS based solution that would do dirty field checking, disabling any form input that has the same value as when the form was loaded, so only changed fields are ever submitted, I like this option best so far, I guess. But it does sound a bit complex, and involves dumping my models to JSON on the page for the form submit handler to compare against.
But again, I'm sure I'm not the first person to have this problem. So is there a standard solution for this?
Have you checked this: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html ?
UPDATE
Well, it doesn't really explain what to do if lock_version is wrong, but at least it's better than updated_at I guess. It all depends on who wins and why. If Sally didn't touch price it seems reasonable to update price from Joe's data when saving. Just add original values as hidden fields and compare them with Sally's input when saving in case lock_version is wrong. If they both modified same field, well, no luck. Somebody should win, or you can go back to the edit page and highlight changes for acceptance.
Related
I have a page that is a report from a database and I'm working on modifying how the filtering works. The intention is to allow the user to select possible values form a list that will be used to filter the resulting report. There are too many values to do this with checkboxes. I'm defining a multiple selection list box with this:
<g:select name="country" from="${countryDataList.KOUNTRY}" value="${params.country}" multiple="true" />
countryDataList is a List<> of objects with a name and a value which I create in the controller. I'm able to get the selected counties and process them without an issue.
But when the page returns from the controller with the filtered report, only the first selection in the list is selected. It doesn't re-select all of the items that the user selected. I am passing the params.country object back from the controller as
country:params.country
I saw some posts about this not working, but they are all from several years ago. Am I missing a vital step?
Ahh sorry, I was reading it on the phone initially and missed the point.
So what you want is a way of sending a multiple select box to a confirmation page. If I understand correctly?
Anyways how many objects in the select are we talking massive or a dozen couple of dozen or so ?
What I did was use check boxes and did a confirmation which shows the selection ticked in check boxes.. So this is the confirmation page that loads in https://github.com/vahidhedayati/mailinglist/blob/master/grails-app/views/mailingListEmail/confirmcontact.gsp
this page which is where multiple attachments selected from the schedule re-appear...
https://github.com/vahidhedayati/mailinglist/blob/master/grails-app/views/mailingListAttachments/_mailerAttachmentsDisplay.gsp.
Please note advice below is all conceptual stuff and there may be easier ways than this
Other than that You could create a taglib call on the confirmation page https://github.com/vahidhedayati/ajaxdependancyselection/blob/master/grails-app/taglib/ajaxdependancyselection/AutoCompleteTagLib.groovy#L55 which takes in your arrayList you could probably convert it to JSON pass it into the javascript that you load in within the taglib (on mine further down it loads this page in)
https://github.com/vahidhedayati/ajaxdependancyselection/blob/master/grails-app/views/autoComplete/_selectJs1.gsp#L23
and look to reselect them using javascript... as I say I haven't tested the last bit, the first bit i.e. checkbox works it is/has been in use.
Years later from you I just had the same problem. What I figured out is: it happens when params.country is an array instead of a Collection (i.e. an ArrayList).
A workaround for this if you want to stick to the array type is at the value attribute of the tag doing this: params.country?.findAll().
I have about 20 forms, each with 15-20 textbox inputs each.
Once the user submits the form, all their values need to be confirmed, this is done by replacing each textbox with a label control that shows the entered value.
The user may click on a back button to edit the data, in which case the textboxes re-appear, or they can confirm their data submission.
What would be the best way to handle this in MVC?
Thanks
I would recommend having different views for editing and showing data. This could be useful if you would like to omit or add some extra of the fields, keeping your view logic simple. You could store the form data in the database with some flag indicating that it is not confirmed yet. After confirmation you would only change the flag of the record. Another option is to store form data in tempData or Session and save it after confirmation.
The quickest way would probably be to have both on the page and bound to the same Model properties but wrap them in some simple render logic. an example off the top of my head in razor could be something like
#if (is in edit state){
<field markup>
#}
else{#
<label markup>
#}
Its been a while since I've worked on an MVC app but that's how i would have done it back then i think.
I've been reading about adding Honey pot fields to my forms for combating bots/spam. Only problem is theirs no guides or anything on where to start. Many sites say to make a field that is hidden that only the spam bot would fill out. But as I'm new to this, don't know where I would start in my application. Could anyone give me the advice on how to set this up? I am trying to make my Devise registration page use honey pot fields.
The basic idea behind honeypot captchas is that you have a hidden (via CSS) field named something like "form" or "email" or "content" that (to a bot just reading the field name) looks like it should be filled in. Then, when the server looks at the submission, you make sure these hidden fields are blank. If they aren't, then you flag the post as a bot.
Here's a well explained example (with some code in ASP), and here's a Rails Gem that provides honeypot captchas.
That Rails Gem I linked looks like it's very easy to use once installed:
<% form_tag comments_path, :honeypot => true do -%>
...
<% end -%>
Although if you're interested in learning about the approach rather than just having it implemented, I'd recommend you roll your own. If you're rolling your own, it's important to make sure that the field is hidden by CSS (or some other style/positioning trick) and not input type="hidden" - as otherwise the bot might not fill out the field.
As Michael Mior pointed out in the comments, it's important to have a message next to the hidden field telling the user to leave it blank - otherwise users with screen readers might erroneously fill it in. This feature is missing from the gem I linked to - so if you're making an accessible website (which you almost certainly should be) you may need to modify it or roll your own.
Keep in mind that this trick isn't foolproof - there's nothing stopping a bot from rendering the page and determining which fields are actually visible to the user before filling any in - but that kind of bot would be considerably more complex than one that just looked at the form html. A honeypot captcha is likely to be very effective at stopping simple bots.
Try invisible_captcha (supports Rails 3, 4 and 5).
It works pretty well for small and medium (in terms of traffic) sites, with a simple and flexible approach. It also provides time-sensitive submissions.
Basic usage
In your form:
<%= form_for(#topic) %>
<%= invisible_captcha %>
...
<% end %>
In your controller:
class TopicsController < ApplicationController
invisible_captcha only: [:create, :update]
...
end
HTML -
<input type="text" name="verifyEmail" id="verifyEmail">
PHP Validation -
if(strlen($_POST['verifyEmail']) > 0){
header('location: {some redirect URL here..}'); //Send them way away from your form :)
die(); //Stop execution of the script
}
CSS -
#verifyEmail{
position:fixed;
visibility: hidden;
top:-500px; left:-500px;
}
dislplay: none; does not show to a bot in HTML (try it with view source)
visibility: hidden; left:-500px; top:-500px; (displays when you view source)
I used display:none honey pots for a while, then switched to visibility option when it occurred to me that the field didn't show in the source code. Do it with a class or id in CSS, not inline style. Notify users with label is good idea, and name is not so important because most bots generally fill in all fields.
Definitely not a catch all but very effective if used with a basic math captcha.
I will share what works 100% for my site right now.
For almost a week we have been testing ways to prevent the high number of fake users called "Spam Bots" as well as "Brute Force Registrations" both are FAKE USERS.
You can find on the internet many ways to apply what is called a honeypot or a hidden field in the registration form.
The purpose of this trick is we fool the FAKE REGISTRATION as it will always fill data in the hidden field thus causing the registration process to DIE preventing the fake registrations.
Now we mentioned many variations of this trick can be found on the internet, and we will explain why our code is quoted as 100% working as for 2 days now it stopped all SPAM BOTS, and all Brute force registrations.
The secret is how we hide the field with a name like "field1" as bots will catch on if we use a common name like password or zip code etc. Using a name like field1 and autocomplete = off force the BOTS to fill in the field and prevents it from determining what the field is for, so it will keep filling it in with data killing the registration attempt.
This image below shows the code we used in the registration form.
<input type="text" name="field1" style="display:none !important" tabindex="-1" autocomplete="off">
This image below shows the code we placed in the PHP form that processes the command to kill the registration if data is entered into the field
if(!empty($_POST['field1'])) die();
For the past 48 hours this code has yielded ZERO SPAM BOTS and ZERO Brute Force Registrations. Enjoy from all of us at AFFA Social
If you wish to manually test this code simply remove the style="display:none from the registration form code above. Try to register putting data in the hidden field, and then registration dies, and if you remove the data from the field the registration will continue.
<div id="honeypotdiv">
If you see this, leave it blank. Only bots should see this
<input type="text" name="body" value="" />
</div>
In my rails 3.1 app, I have a Timesheet model. A Timesheet belongs to a Track. A Track has many TimingEyes.
When I create a new Timesheet and select its Track (via a select menu), I need to dynamically display a group of checkboxes for choosing Timing Eyes that were activated that day. At the moment I can display all the timing eyes available in my database, however there are a dozen tracks each with several timing eyes. This is way too much information on the new Timesheet form.
Is there a way I can limit the group of Timing Eyes to the track_id chosen in my select menu? Would there be an advantage to making this a multistep form?
Multi step form wouldn't be a bad thing here and would remove complexity... if you want to stay with a single page form though, this sounds like a great time for some jquery.
Use .change to fire whenever the select box changes value.
When this fires use .get (ajax) to render your "checkbox" section html.
So a basic boilerplate would look something like this:
$("#trackselect").change(function () {
$.get('yoururl', function(data) {
$('#checkboxsection').html(data);
});
})
With this setup you need to define a url/page that outputs the checkboxes html for that particular track. Maybe something like (http://yourdomain.com/tracks/:id/checkboxes).
Hope this helps
The best public example that I can think of off the top of my head would be the amazon shopping cart. Where you have a page that displays multiple distinct records that can have multiple distinct fields updated.
I can't put each one in a form tag because the user may modify more than one record and then submit.
I can't just update all the records that I get back because:
1. Performance
2. Auditing
3. If someone changed the record that the user 'didn't change' when they were viewing the page and then the user submits those changes would be overwritten.
So how to best handle getting the data back and then getting which records where changed out of that?
Is that clear?
Use binding! Don't be iterating the form collection in your actions.
Steve Sanderson wrote a blog post about how to do it. I wrote a blog post on how to do it with MvcContrib.FluentHtml. Both posts are very detailed and include downloadable code.
Generate your form in a repeater, and append an ID to the form elements that increments with each new form. Save the number of repeated form elements in a hidden field. Then in your controller, read the value of this hidden field - that'll be the number of forms to read. Then, in a loop, retrieve each form's fields by specifying the name of the field, plus the loop index appended to the name, as the key.
You can use some javascript logic to detect when a form's value changes, and update a hidden field in that form's section if that occurs; or you can hide the original values inside a hidden field with each form section (although I don't recommend this as too many fields / forms will bloat your page).
one (but not necessarily the best) approach is to store which items are changed in a js-variable or something on the client side as they are changed, and then only send the data that is actually different from what the user recieved.
and as Erik stated, you could use hidden form elements to make sure that it works without js as well.