Making sure only one user is editing a form in Rails application - ruby-on-rails

Currently, I have a Rails application whose edit form is on a separate edit page. Is there a way to make sure no two users are accessing the edit page at the same time? Or a user can only access the edit page if no other user is currently on the page?
Or to ask a simpler question, is there a way to get a list of users currently on the page?
I am on Rails 4.

HTTP is a stateless protocol. It was designed to allow idempotent transactions. The server does not store transaction state information about each chain of requests. The session allows you to mitigate this design pattern and allow the server to track where your users have been. In order for you to know if a user is on a page, you will need to store in your database where each user is. Remember, that when a user decides to navigate away from a page, your servers will not know it, only when a request is made to a different page.
I assume you don't need to track anonymous session information, so you probably need to override your controller action that ensures users are logged in to save where the user is at. Before rendering the page, ensure the count of user's current location equal to the rendered page is 0.
You can have AJAX fire on the page, updating the location of your user on these pages so you can ensure that there has been no user in a reasonable timeout. Without the AJAX you would need to consider what the reasonable amount of time a user would be editing information, and consider that a non-reasonable amount of time is likely the actual amount.
There's no 'RAILS' feature that can be turned on to check where a user is located, this would be a roll your own situation.

I think the best way is to use a Redis Store (or anything in memory), or make a temporary sessions table for that.
Then you can authorize the show action to check whatever you want.

Related

Rails: Ask for register after submit content?

In my Rails App, I made a form_for to allow any visitor to submit their content.
But after submit, I want to ask user, whether they want to register for this site or not.
There are some approach to this:
Redirect after user submits the form, left the initial post anonymous.
Much the same as the first one. But somehow help user to reclaim the post they just make
Store the content in some place first and do not submit. Instead, ask for register. And after register, show the stored content before and ask user to submit again.
Basically, I can implement the 1st method. But it seems just not that good. For the 2nd and 3rd one, I do not know how to reclaim the post or store content beforehand.
Is there a standard way to do this? How can I solve this problem?
For solving the same kind of problem, I chose your 3rd option. For that you can use sessions, it will allow you to keep some information in memory related to a specific connection to your server.
http://guides.rubyonrails.org/action_controller_overview.html#session
There are some ways.
First of all you need to keep in mind that these are different behaviors from which you should chose first and do not let the implementation force you to chose one.
For the second case you can have the id of the post that was created (along with some guarantees that it is an orphan post) and then tweak your register method to also assign a post to a user after creating one.
The Third case can be implemented by storing the post data either to session or to a backend temporary store and retrieve them if needed.

How do I see real-time activity of my users in Rails 3?

What I would like to do is have my admin user be able to see - in real time (via some AJAX/jQuery niceness) - what my user's are doing.
How do I go about doing that ?
I assume it has something to do with session activity - and I have started saving the session to the db, rather than the cookie.
But generally speaking, how do I take that info and parse it in real time ?
I looked at my session table and aside from the ids (id and session_id), I see a 'data' field. That data field stores a hash - which I can't make any sense of (looks like an md5 hash).
How would I use that to see that User A just clicked on Link B, and right after that User B clicked on link A, etc. ?
Is there a gem - aside from rackamole - that might be able to help me?
You might want to check out Mixpanel. They are easy to setup and have some of what you are asking for.
The session data only contains the values stored in the session[]-hash from the user. It doesn't store which action/controller was called, so you don't know which "link was clicked".
Get the activity of your users:
Besides rackamole you have two options IMHO.
Use a before_filter in your ApplicationController to store the relevant info you are interested in. (Name of controller, action or URI, additional parameters and id of the logged in user for example).
Use an AJAX-call at the bottom of each page which posts back the info you are interested in (URI, id of logged in user, etc.) to your server. This allows faster response times from the server, as the info is stored after the page has already been delivered. Plus, you don't have to use a Rails-request to store it. The AJAX-request could also be calling a simple PHP-script writing the data to disk. This is much faster.
Storing this activity:
Store this data/info either in the database or in a logfile. The database will give your more flexibility like showing all actions from one user, or all visitors for one page, etc. The logfile solution will give you better performance.
Realtime vs. Oldschool:
As for pulling out your collected data in realtime, you have to build your own solution. To do this elegantly (without querying your server once a second to look if new data has arrived) you'll need another server process. Search for AJAX Push for more info.
Depending on your application I'd ask myself if realtime notifications for this are really necessary (because of all the hassles of setting this up).
To monitor the activity on your site, it should be enough to have a page listing the latest actions and manually refresh it (or refresh it automatically every ten seconds).
Maybe you can test https://github.com/raid5/acts_as_scribe#readme
It works with Rails 3 too.

voting - stopping abuse from client side - ASP.NET MVC

so I have designed this voting thing which does not let somebody vote for the same article twice in 24 hours. However, suppose a person votes and after seeing the person was able to cast vote or that he is falling in that 24 hour window, I disable the vote-casting button (and this is all Ajax btw).
But what to do when a person closes his/her browser and comes back up or even refreshes the page? Obviously, he would not be able to cast vote, because of my algorithm, but the person would still end up succeeding in making call to the server. So if he really wanted, he would keep refreshing the page and clicking on the vote and put unnecessary load on the server. How to avoid that by doing some sort of client-side thing or something?
I am using ASP.NET MVC, so session variables are out of question.
Am I being over-concerned by this?
If voting happens only from logged in (known) members then you shouldn't have any problem.
If, on the other hand, everyone can vote then you need to store all user vote events:
timestamp
poll
poll_vote
ip
user agent
user uniqueness cookie
So you'll need a random hash sent out as cookie. This will ensure that you don't accept another vote for the same poll from the same person.
If the user deletes his cookies you fallback to plan B, where you don't allow more than (say) 10 votes from the same IP and user agent combination for 24 hours.
The system is not perfect since users can change IPs and (more easily) user agents. You'd need advanced pattern detection algorithms to detect suspicious votes. The good thing about storing all user vote events is that you can process these later on using a scheduler, or outsource the votes to someone else who can process them for you.
Good luck
Refreshing is not a problem
If you're doing all this voting using Ajax, refreshing a page won't do anything except load the page using GET.
If you're not using Ajax you should make sure you call RedirectToAction/RedirectToRoute action result, that would as well help you avoid refresh problems.
How do you recognise users
If you use some sort of user authentication this re-voting is not a problem. But if your users are plain anonymous, you should store IP address with your votes. This is how things are usually done. This makes it possible to avoid session variables as well. But you have to be aware of this technique because it's not 100% perfect.
Cookies?
You could of course also use absolute expiration cookies. They'd expire in an day. Advanced users would of course be able to avoid your voting restrictions, but they would be able to avoid other ways as well. Sessions BTW are also based on cookies anyway.
Combination
But when you'd like to make you system as great as possible, you'll probably use a combination of the above.
The best way would be to track who voted for what and when on the server (probably storing it in a database). In order to do this you must use an authentication system on your site (probably forms authentication) to identify users. So every time someone tries to vote you check first in your data storage if he already voted and when and decide whether to validate the vote or not. This is the most reliable way.
If your site is anonymous (no authentication required to vote) then you could store a persistent cookie on the client computer that will last for 24 hours and indicate that a vote has already been cast from this computer. Remember though that cookies might be disabled, removed and are not a reliable way to identify a given user.
I am using ASP.NET MVC, so session
variables are out of question.
Any reason for that? Sessions are perfectly fine in ASP.NET MVC applications. It is in your case that they won't work because if the user closes the browser he will lose the session.
Obviously, he would not be able to
cast vote, because of my algorithm,
but the person would still end up
succeeding in making call to the
server. So if he really wanted, he
would keep refreshing the page and
clicking on the vote and put
unnecessary load on the server
Automated bots could also put unnecessary load to your server which is much more important than a single user clicking on F5.
If you just want to ensure the user can only vote once on an article then you just need to store a Set (i.e. HashSet) of all article id's that they've already voted on, then just check before allowing the vote.
If you still wanted a 24hr limit then you need to store a Dictionary<articleId,DateTime> then you can check if he has already voted for that article and if he has when it was.

How to automatically maintain a table of users that have been authenticated by IIS 7.0 using Windows Authentication

I want to build and maintain a table of users. All users that access the ASP.NET MVC site are authenticated via Windows Authentication so they're bound to have a unique username. I'm grabbing the user name from:
System.Web.HttpContext.Current.User.Identity.Name
I feel like I could go two ways with this.
Anytime the user table or any tables that references the user table are accessed, I could add the user if it doesn't exist. I'm worried this might be very error prone if user's existance isn't checked.
Anytime the user visits any page on the site, check if that user exists in the db and if they don't exist, add the user. This may have a lot of overhead as it'll be checked every page change.
I'd like to hear which of these is the better solution and also how to implement them.
I think a better way would be something similar to the option two.
Anytime a user visits a page, check a session variable to see if that user was checked against the DB. If the session variable is not there, check if that user exists in the DB, add the user to your table if necessary, then set the session variable.
That way you don't have to hit the DB on every request.

rails: how to detect other clients browsing the same url

What want to be accomplished is:
I want to "synchronize web browsers". my site has a "wait URL" where when browser gets there it will be kept waiting till another browser also go there and then both will be presented with a quiz-like game.
Right now the wait url will call each second to Rails to check if other player came to the game. How can in the Rails framework detect a different client connecting to the same URL?
As the controller is recreated per request looks like is not the place, not the view for sure and storing this in the model looks really clumsy.
Also, after the pairing I need to check and compare every answer of the paired users so somehow that information must be retained
What you're trying to do is share information between users. So the database or memcached are the most sensible.
Simplest: I'd create an ActiveRecord object, perhaps called Quiz, instances of which people join by virtue of going to a URL, e.g using default routes:
http://yoursite.com/quizes/join/3434
You'd need an ajax poller poller to notify the others; use periodically_call_remote for this -- you could use render :nothing => true by default and render something else if there was an error to keep it efficient. You can also use the frequency method as a basis to determine whether people leave the quiz as well (e.g. if frequency is 1s, then assume someone has left if they didn't ping after 5-10s).
Assuming these users are not registered with the site so don't have some kind of user id you could store I would suggest using the session. It is a per user data store. By default the session is stored in an encrypted cookie on the users machine. However you can use ActiveRecord as the session store and could maybe query that table directly?
Store the URL in the session and do a search for it at a later time. You can normally only access the current users session using the Rails 'session' hash but maybe (untested) if you created a model called Session (or maybe something more specific like 'WaitingGamers') which used the sessions table you could lookup the information you need.
I would guess when using ActiveRecord as the session store the session data is stored as a serialised hash. Use Marshall to turn it back in to a regular hash and find the data you stored in there.
I'm not a rails expert, but since all the state resides in your database that would be the place to keep this information.
You could keep a "waiting users" table, and in the "wait URL" view check if the user is already in the table. If not, add him to the table. Then, check if there is another user waiting (maybe there's more than one?) and if so, match them up and delete them from the table.
Another improvement would be to keep a timestamp for each user in the "waiting users" table, which gets updated in the view - this would serve as a keep-alive that will enable you to detect users that left the "wait URL" page or closed the browser.

Resources