<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kev.in &#187; Controllers</title>
	<atom:link href="http://kev.in/category/controllers/feed" rel="self" type="application/rss+xml" />
	<link>http://kev.in</link>
	<description>"It was a musical thing and you were supposed to sing"</description>
	<lastBuildDate>Thu, 13 Nov 2008 09:23:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to limit users to one vote per IP address</title>
		<link>http://kev.in/2008/01/18/how-to-limit-users-to-one-vote-per-ip-address.html</link>
		<comments>http://kev.in/2008/01/18/how-to-limit-users-to-one-vote-per-ip-address.html#comments</comments>
		<pubDate>Fri, 18 Jan 2008 16:52:52 +0000</pubDate>
		<dc:creator>Kev.in</dc:creator>
				<category><![CDATA[Controllers]]></category>
		<category><![CDATA[Migrations]]></category>
		<category><![CDATA[Models]]></category>

		<guid isPermaLink="false">http://railsauthority.com/tutorial/how-to-limit-users-to-one-vote-per-ip-address</guid>
		<description><![CDATA[A reader Aaron J. writes in response to the short article How to obtain the IP address of the current user:
Do you have any advice on how I can take this a step further? I am looking to limit a given user to one vote per session but I’m not sure how to achieve this. [...]]]></description>
			<content:encoded><![CDATA[<p>A reader <strong>Aaron J.</strong> <a href="/2007/08/26/how-to-obtain-the-ip-address-of-the-current-user.html#comment-6">writes</a> in response to the short article <a href="/2007/08/26/how-to-obtain-the-ip-address-of-the-current-user.html">How to obtain the IP address of the current user</a>:</p>
<blockquote><p>Do you have any advice on how I can take this a step further? I am looking to limit a given user to one vote per session but I’m not sure how to achieve this. I’d appreciate any help you can offer. Thanks for your time.</p></blockquote>
<p>Good question, Aaron. Remember that a session is simply tied to your browser cookie, so if we allow one vote per session, all the user has to do is clear their cookies and then vote again. And again. And again! So I think what you mean is how do we allow only one vote per IP address? To enforce that, we&#8217;ll need to save a list of the IP addresses that have already sent us a vote. And before we record a vote, we need to make sure their IP address isn&#8217;t already on that list. Further, we should remember which poll number they have voted in so we can have more than one poll in our application. We&#8217;re going to need a simple table:</p>
<pre name="code" class="ruby:nocontrols:nogutter"># lib/db/migrate/001_voter_log.rb
create_table :vote_log do |t|
  t.column :poll_id, :integer
  t.column :client_ip, :string
end
</pre>
<p>For simplicity of this example, we&#8217;ll put all of our logic in the controller. (I won&#8217;t show the VoteLog model class because it&#8217;s empty.)</p>
<pre name="code" class="ruby:nocontrols:nogutter">
# RAILS_ROOT/app/controllers/poll_controller.rb
def record_a_vote
  poll_id = params[:poll_id]
  client_ip = request.remote_ip

  unless VoteLog.count(:all, :conditions => ['poll_id = ? AND client_ip = ?', poll_id, client_ip]) == 0
    redirect_to :already_voted
  end

  Poll.find(poll_id).record_vote(params[:candidate]) # Or however you count votes
  VoteLog.create(:poll_id => poll_id, :client_ip => client_ip)
end

def already_voted
  render :text => "You already voted, no cheating!"
end
</pre>
<p>Just keep in mind this approach might not be appropriate in all situations. Due to Network Address Translation (NAT) firewalls, many thousands of people will appear to have the same client_ip. This is particularly true in corporate environments. If that&#8217;s a concern, you&#8217;ll need to go with a full-blown registered-user approach.</p>
<h3>Further Reading</h3>
<p><a href="/tutorial/how-to-obtain-the-ip-address-of-the-current-user">How to obtain the IP address of the current user</a></p>
<h3>Feedback and Article Ideas</h3>
<p>Want to see a topic explored here? <a href="/contact">Send Me a Message</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kev.in/2008/01/18/how-to-limit-users-to-one-vote-per-ip-address.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Restoring Rails session data when cookies aren&#8217;t available</title>
		<link>http://kev.in/2007/08/30/restoring-rails-session-data-when-cookies-arent-available.html</link>
		<comments>http://kev.in/2007/08/30/restoring-rails-session-data-when-cookies-arent-available.html#comments</comments>
		<pubDate>Fri, 31 Aug 2007 03:04:00 +0000</pubDate>
		<dc:creator>Kev.in</dc:creator>
				<category><![CDATA[Controllers]]></category>
		<category><![CDATA[Filters]]></category>

		<guid isPermaLink="false">http://railsauthority.com/tutorial/restoring-rails-session-data-when-cookies-arent-available</guid>
		<description><![CDATA[
If you&#8217;ve ever needed to implement user-friendly upload, you know intimately what a pain it is to get right. The web just isn&#8217;t built for uploading files from a browser. I mean, it kinda works, but even then only with a dozen or so limitations. Even the major photo and video sites have tried various [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" src="http://railsauthority.com/wp-content/uploads/cookie.jpg" title="C is for Cookie" alt="C is for Cookie" height="125" width="180" /><br />
If you&#8217;ve ever needed to implement user-friendly upload, you know intimately what a pain it is to get right. The web just isn&#8217;t built for uploading files from a browser. I mean, it kinda works, but even then only with a dozen or so limitations. Even the major photo and video sites have tried various solutions to make this easier for users. So when I built <a href="http://dibs.net">Dibs.net</a>, I decided rather quickly to abandon all hope of getting it working flawlessly with plain ol&#8217; Javascript and HTML, and instead looked into using a fairly nonintrusive Flash uploader component. (Without Flash installed, it just falls back to a simple HTML-based file-upload form.)</p>
<p>That&#8217;s not to say it was perfectly simple to get working with Rails. Because Dibs.net accepts uploads only from logged-in users, I ran into two limitations that would not allow me to use this solution:</p>
<ul>
<li>Flash doesn&#8217;t send the cookies from the browser (at least it doesn&#8217;t in Firefox; it might in IE)</li>
<li>Rails doesn&#8217;t support non-cookie sessions</li>
</ul>
<p>Because Flash doesn&#8217;t send the session cookie, Rails thinks the request is coming from a new, logged-out user and creates a new session for it. Adding a cookies feature to Flash was well out of my hands since I don&#8217;t work for Adobe, so I looked into a way to restore the session from a session key passed as a URL parameter. After some experimentation, I found a solution that works great.</p>
<p><span id="more-116"></span></p>
<h3>Assumptions</h3>
<p>I use a modified version of the <code><a href="http://technoweenie.stikipad.com/plugins/show/Acts+as+Authenticated">acts_as_authenticated</a></code> plugin. Upon authentication, the plugin sets the <code>:user</code> session key to the authenticated user&#8217;s <code>id</code>. You&#8217;ll need to adapt for your own configuration.</p>
<h3>Example Rails Code</h3>
<p class="code-source">In <span class="filename">RAILS_ROOT/app/controllers/show_my_ip_controller.rb</span>:</p>
<pre name="code" class="ruby">
class ImagesController &lt; ApplicationController
	session <img src='http://kev.in/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> ff, <img src='http://kev.in/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> nly =&gt; :create
	prepend_before_filter :restore_session_user_from_param, <img src='http://kev.in/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> nly =&gt; :create
	requires_login :except =&gt; :index

	def create
	  # Handle the file upload here
	end

	private
	def restore_session_user_from_param
	    data = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager].session_class.find_session( params[:_session_id] ).data
	    sess_obj = Marshal.load( Base64.decode64( data ) )
	    @current_user = User.find( sess_obj[:user] )
  	rescue
    	authorization_required
  	end
end</pre>
<p class="code-source">Then we include the session id as a parameter in the form&#8217;s action URL in the view:</p>
<pre name="code" class="ruby:nocontrols">
&lt;form action="&lt;%= images_path(:_session_id =&gt; session.session_id) %&gt;" method="post" id="photoupload" enctype="multipart/form-data"&gt;</pre>
<h3>How it works</h3>
<p>Under normal circumstances the <code>acts_as_authenticated</code> plugin sets the <code>@current_user</code> instance variable to the current logged-in user at the start of each request. Since we have no session data when a Flash app hits the controller, there&#8217;s effectively no <code>current_user</code>. Our goal is to get <code>current_user</code> working, so we:</p>
<ul>
<li>turn sessions off for the relevant action; otherwise Rails will create useless sessions any time Flash hits that action</li>
<li>prepend a before filter to set the <code>@current_user</code> instance variable</li>
<li>require login for most of the actions, including <code>create</code></li>
</ul>
<p>In the before_filter, we grab the session data from whatever session store we&#8217;re using, decode and unmarshall it, and set the @current_user instance variable to the <code>User</code> we find with the <code>id</code> we get from the session hash.</p>
<p>Simple? Not really. But it works!</p>
<h3>Further Reading</h3>
<p>I couldn&#8217;t find much documentation on any of this beyond stomping through the Rails code &amp; <a href="http://corelib.rubyonrails.org/classes/CGI/Session.html">Ruby&#8217;s CGI Standard Library docs</a>.</p>
<h3><strong>Update:</strong> A Word of Caution</h3>
<p>I forgot to mention when I published this earlier that there&#8217;s a reason parameterized sessions is discouraged: browsers will send the entire current link, including the session id, in referer headers to offsite hosts. This doesn&#8217;t affect Dibs.net&#8217;s Flash upload, but in other scenarios use the above with caution, or with SSL.</p>
<h3>Feedback and Article Ideas</h3>
<p>Want to see a topic explored here? <a href="/contact">Send Me a Message</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kev.in/2007/08/30/restoring-rails-session-data-when-cookies-arent-available.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to obtain the IP address of the current user</title>
		<link>http://kev.in/2007/08/26/how-to-obtain-the-ip-address-of-the-current-user.html</link>
		<comments>http://kev.in/2007/08/26/how-to-obtain-the-ip-address-of-the-current-user.html#comments</comments>
		<pubDate>Mon, 27 Aug 2007 05:56:38 +0000</pubDate>
		<dc:creator>Kev.in</dc:creator>
				<category><![CDATA[Controllers]]></category>

		<guid isPermaLink="false">http://railsauthority.com/tutorial/how-to-obtain-the-ip-address-of-the-current-user</guid>
		<description><![CDATA[
Web applications can receive requests directly, via a CGI process, through proxy servers, relayed from front-end web servers, and so on. This can complicate how you might find out where the request originated if you, for example, wanted to limit an online poll to one vote per IP address. Luckily, Rails consolidates most of the [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" src="http://railsauthority.com/wp-content/uploads/address.jpg" title="Some house address" alt="Some house address" height="88" width="160" /></p>
<p>Web applications can receive requests directly, via a CGI process, through proxy servers, relayed from front-end web servers, and so on. This can complicate how you might find out where the request originated if you, for example, wanted to limit an online poll to one vote per IP address. Luckily, Rails consolidates most of the ways to get this info into a single convenience method on the <code>request</code> object for us.</p>
<p><span id="more-113"></span></p>
<h3>The Convenience Method: <code>#remote_ip</code></h3>
<p>Without the <code>request.remote_ip</code> method, you&#8217;d have to look for specific headers that are used to carry this data in the HTTP request beyond the server where the actual client&#8217;s connection was terminated.</p>
<p>Rails&#8217; <code>request.remote_ip</code> method is pretty smart: it looks for and parses the headers <code>HTTP_CLIENT_IP</code>, <code>HTTP_X_FORWARDED_FOR</code> and <code>REMOTE_ADDR</code> and parse the value which are commonly used for this purpose.</p>
<h3>Example Rails Code</h3>
<p class="code-source">In <span class="filename">RAILS_ROOT/app/controllers/show_my_ip_controller.rb</span>:</p>
<pre name="code" class="ruby">
class ShowMyIpController &lt; ApplicationController

  def index
    @client_ip = request.remote_ip
  end

end
</pre>
<p class="code-source">In <span class="filename">RAILS_ROOT/app/views/show_my_ip/index.html.erb</span>:</p>
<pre name="code" class="xml:nocontrols:nogutter">
Your IP address is &lt;%= @client_ip %&gt;
</pre>
<h3>Further Reading</h3>
<p>The <code>request.remote_ip</code> method is documented in the <a href="http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html#M000235">Rails Framework rdocs</a>.</p>
<h3>Feedback and Article Ideas</h3>
<p>Want to see a topic explored here? <a href="/contact">Send Me a Message</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kev.in/2007/08/26/how-to-obtain-the-ip-address-of-the-current-user.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
