Search code examples
ruby-on-railsruby-on-rails-4session-cookies

How do I manually set cookie in rails app?


I have a situation where I need to send session id in custom header because safari does not allow sending cookie from iframe.

But now, I'm having trouble setting the cookie from rack middleware.

status, headers, body = @app.call(env)
session_id = headers['X-SESSION-ID'] || headers['HTTP_X_SESSION_ID'] || headers['x-session-id'] || ''

if !headers['Cookie'].present? && session_id.present?
  headers['Cookie'] = {
    '_session_id': {
      value: session_id,
      path: '/',
      httpOnly: true
    }
  }
end

Or is there way to manually set session id without having to fetch it from cookie?

Update 1:

Modifying rack request files does work. But, I'm not sure how to proceed with this one. If nothing works then, I might manually update this file in all servers.

def cookies
  hash   = @env["rack.request.cookie_hash"] ||= {}
  string = @env["HTTP_COOKIE"] || "_session_id=#{@env["HTTP_X_SESSION_ID"]}"

  return hash if string == @env["rack.request.cookie_string"]
  hash.clear

  # According to RFC 2109:
  #   If multiple cookies satisfy the criteria above, they are ordered in
  #   the Cookie header such that those with more specific Path attributes
  #   precede those with less specific.  Ordering with respect to other
  #   attributes (e.g., Domain) is unspecified.
  cookies = Utils.parse_query(string, ';,') { |s| Rack::Utils.unescape(s) rescue s }
  cookies.each { |k,v| hash[k] = Array === v ? v.first : v }
  @env["rack.request.cookie_string"] = string
  hash
end

Looks like modifying the cookie method as above do not work.


Solution

  • Finally I managed to solve it. So, I added rack_request.rb in initializers. And here's the code for it:

    require 'rack'
    require 'rack/request'
    require 'rack/utils'
    
    Rack::Request.class_eval do
     def cookies
        hash = @env["rack.request.cookie_hash"] ||= {}
        string = @env["HTTP_COOKIE"] || "_session_id=#{@env['HTTP_X_SESSION_ID']}"
    
    unless string =~ /\s*_session_id=/i
      if  @env['HTTP_X_SESSION_ID'].present?
        string << "; _session_id=#{@env['HTTP_X_SESSION_ID']}"
      end
    end
    
    # require 'colorize'
    #
    # Rails.logger.info 'from cookies'.green
    # Rails.logger.info (string.blue)
    
    return hash if string == @env["rack.request.cookie_string"]
    hash.clear
    
    
    # According to RFC 2109:
    #   If multiple cookies satisfy the criteria above, they are ordered in
    #   the Cookie header such that those with more specific Path attributes
    #   precede those with less specific.  Ordering with respect to other
    #   attributes (e.g., Domain) is unspecified.
    cookies = Rack::Utils.parse_query(string, ';,') { |s| Rack::Utils.unescape(s) rescue s }
    cookies.each { |k, v| hash[k] = Array === v ? v.first : v }
    @env["rack.request.cookie_string"] = string
    hash
    
    
     end
    end
    

    And I'm sending 'X-SESSION-ID' in my ajaxHeaders for session id.