8

Normalmente non memorizzerei oggetti in una sessione di Rails ma sto usando una libreria che richiede questo. Ho avuto un problema molto strano in cui un oggetto memorizzato appare come una stringa dopo il reindirizzamento.L'oggetto memorizzato nella sessione di Rails diventa una stringa?

di riprodurre ho creato un campione Rails 4.1 app

$ rails new session-test

Aggiunto un controller di test:

class HomeController < ApplicationController 
    def index 
    logger.debug "session[:customer]: #{session[:customer]}" 
    logger.debug "session[:customer].name: #{session[:customer].name}" 
    end 

    def from 
    Struct.new 'Customer', :name, :address 
    session[:customer] = Struct::Customer.new 'Dave', '123 Main' 
    redirect_to :action => :index 
    end 
end 

percorsi di impostazione:

Rails.application.routes.draw do 
    get 'home/index' 
    get 'home/from' 
    root 'home#index' 
end 

Poi apro il Rotaie

$ bundle exec rails server

e ha colpito localhost: 3000/home/da nel browser:

Started GET "/home/from" for 127.0.0.1 at 2014-04-09 21:20:25 -0700 
Processing by HomeController#from as HTML 
Redirected to http://localhost:3000/home/index 
Completed 302 Found in 18ms (ActiveRecord: 0.0ms) 


Started GET "/home/index" for 127.0.0.1 at 2014-04-09 21:20:25 -0700 
Processing by HomeController#index as HTML 
session[:customer]: #<struct Struct::Customer name="Dave", address="123 Main"> 
Completed 500 Internal Server Error in 2ms 

NoMethodError (undefined method `name' for "#<struct Struct::Customer name=\"Dave\", address=\"123 Main\">":String): 
    app/controllers/home_controller.rb:4:in `index' 

Non ho idea del perché questo oggetto è sempre tradotto come una stringa ...

Sembra di avere a che fare con il tipo di archivio di sessione di cookie_store perché se cambio

session_store.rb da

Rails.application.config.session_store :cookie_store, key: '_session-test_session'

a

Rails.application.config.session_store :cache_store

funziona!

Qualche idea?

+0

La libreria in questione è la gemma shopify_app utilizzata da molti sviluppatori. Sono d'accordo che è una cattiva idea conservare l'oggetto nella sessione di Rails per una serie di motivi, ma questo è ciò che fa questo gioiello: https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/templates /app/controllers/sessions_controller.rb#L12-L13 Quello che mi chiedo è il motivo per cui questo è borked in Rails 4.1? Non vedo che accada nella loro app di esempio che è 3.2: https://github.com/Shopify/embedded-app-example –

risposta

5

Non è possibile memorizzare oggetti nella sessione di Rails. È un archivio di valori-chiave che accetta solo stringhe perché, il più delle volte, è impacchettato e inviato al client come cookie crittografato.

Non è una discarica per le cose che potrebbero essere necessarie. Fai attenzione a quanta spazzatura ti riempia lì perché più ti appoggi alla sessione, più grande è il cookie che il cliente dovrà tornare al tuo server per ogni richiesta.

Vale la pena osservare le intestazioni nello strumento di ispezione della rete del browser per vedere quanto è pesante l'ingombro delle vostre richieste.

Se davvero hai bisogno di perseverare qualcosa, usa un formato di codifica string-friendly come JSON per essere sicuro di poter recuperare i dati in un formato utilizzabile.

Sarei molto riluttante a utilizzare anche lo cache_store, che non viene condiviso tra diverse istanze dell'applicazione. Gli oggetti ruby ​​esistono solo nel contesto di un singolo processo, quindi altre richieste, che molto spesso colpiranno un processo casuale, non saranno in grado di farne uso con la stessa facilità.

L'archivio di cookie predefinito è il più affidabile. Gli altri che condividono tra i processi dipendono dalla disponibilità di servizi aggiuntivi (Memcached, Redis, ecc.) Ma la maggior parte di essi impone anche una politica di sole stringhe.

+0

La libreria in questione è la gem di shopify_app utilizzata da molti sviluppatori. Sono d'accordo che è una cattiva idea conservare l'oggetto nella sessione di Rails per una serie di motivi, ma questo è ciò che fa questo gioiello: https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/templates /app/controllers/sessions_controller.rb#L12-L13 Quello che mi chiedo è il motivo per cui questo è borked in Rails 4.1? Non vedo che accada nella loro app di esempio che è 3.2: https://github.com/Shopify/embedded-app-example –

+0

È possibile memorizzare le cose in modo affidabile se sono serializzate. Altrimenti è incostante. Non sono sicuro del motivo per cui qualcuno scriverà un codice che dipende dal fatto che funzioni contro ogni previsione. – tadman

0

Ho avuto lo stesso problema con la mia app Shopify e ho trascorso molto tempo a debuggarlo. Basandomi sulla precisa e non dogmatica spiegazione di Tadman, sono stato in grado di aggirarlo con il Marshalling dell'oggetto della sessione. E 'richiesto solo 3 righe di codice per modificare:

login_protection.rb: 12: ShopifyAPI :: Base.activate_session (Marshal :: carico di sessione [: Shopify]) login_protection.rb: 25: Marshal :: carico di sessione [ : Shopify]

sessions_controller.rb: 13: sessione [: Shopify] = Marshal :: dump (sess)

ho postato sul forum Shopify e si aspettano che ti rilasciano un aggiornamento al più presto. Per quello che vale, penso che il vecchio modo, mentre filosoficamente "sbagliato", ha funzionato correttamente in ogni versione di Rails fino alla 4.1.

4

Correggere è eseguire la serializzazione e deserializzazione in modo esplicito, manualmente.

ad es.

# storing... 
session[:customer] = (Struct::Customer.new 'Dave', '123 Main').to_yaml 

# retrieving... 
customer = YAML.load(session[:customer]) 

Per shopify_app gemma, vedi modifiche apportate ai file di richiesta di pull https://github.com/Shopify/shopify_app/pull/90/files e applicare di conseguenza per la vostra applicazione esistente.

Problemi correlati