You correctly understood that the problem with mixing HTTP and https in a standard Rails application is that the session must be insecure (i.e. link through an insecure cookie), which means that it is vulnerable to a session failure.
As you mentioned in your comment on @nmott's answer, one approach is to have both a safe and an insecure cookie.
Instead of referring to two identical sessions, for my purposes, I consider it sufficient to have an unsafe Rails session along with a secure, signed cookie that simply refers to the user_id of the current user. In other words, I donβt need a full copy of the session, something unique for each user (in a secure cookie) that corresponds to an insecure session.
In every action that is accessed via SSL (and has the current user), I verify that the secure signed cookie user_id matches the user ID stored in the insecure Rails session. If there is a coincidence, I assume that everything is fine, and act normally, referring to an insecure session. If there is no match, an error message appears. I accomplish this with the before_filter method, such as:
def verify_secure_user_cookie
Presumably, a legitimate user will always have a secure cookie and they will never see an error message. An attacker will be able to copy an insecure cookie and will not have access to a secure cookie. In this case, he could connect to the session and access non-SSL pages, but he could not access the SSL pages using the victim's session.
Thus, your non-SSL pages are still vulnerable to lateral connectivity, but your SSL pages are not vulnerable to session failures. For this to be effective, you need to enforce SSL for all actions that need to be protected (either from eavesdropping or from session failures). Using force_ssl in a controller is one way to do this, or you can roll your own.