7

Ho guardato RailsCast, un altro video di attributi annidati, molti post SO e ho combattuto con questo per un po ', ma non riesco ancora a farlo capirlo. Spero sia qualcosa di piccolo.Impossibile assegnare in massa attributi protetti per la creazione di un modello nidificato has_many con Devise

ho due modelli, User (creato da Devise), e Locker (aka, un prodotto lista dei desideri), e sto cercando di creare un Locker per un User quando si iscrivono. Il mio modulo di login ha un campo per il nome del loro nuovo Locker (giustamente chiamato :name) che sto cercando di assegnare all'armadietto che viene creato dopo la registrazione di un nuovo utente. Tutto quello che sto sempre accolti con IS:

WARNING: Can't mass-assign protected attributes: locker

Ho provato ogni combinazione di accepts_nested_attributes e attr_accesible in entrambi i miei modelli, ma ancora non funziona nulla. Posso vedere dai log che è elaborato dal Devise # creare metodo, e so Devise non è abbastanza intelligente per creare i miei modelli come voglio :)

Ecco i bit rilevanti delle mie due modelli:

# user.rb  
class User < ActiveRecord::Base 
    attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :locker_attributes 

    # Associations 
    has_many :lockers 
    has_many :lockups, :through => :lockers 

    # Model nesting access 
    accepts_nested_attributes_for :lockers 
end 

e

# locker.rb 
class Locker < ActiveRecord::Base 
    belongs_to :user 
    has_many :lockups 
    has_many :products, :through => :lockups 

    attr_accessible :name, :description 
end 

# lockers_controller.rb (create) 
    @locker = current_user.lockers.build(params[:locker]) 
    @locker.save 

sto assumendo che ho bisogno di sostituire il metodo di Devise create per ottenere in qualche modo a questo lavoro, ma io sono abbastanza nuovo alle rotaie e sto abituando alla scatola nera "magica" natura di tutto questo.

Se qualcuno può darmi una mano, sarei incredibilmente grato. Ho già trascorso troppo tempo su questo come è :)

EDIT: Ho realizzato che ho omesso qualcosa nel mio problema. Il mio modello Locker ha tre attributi - name, description (non obbligatorio) e user_id per collegarlo allo User. Il mio modulo di registrazione richiede solo il name, quindi non sto eseguendo il ciclo di tutti gli attributi nel mio modulo annidato. Potrebbe avere qualcosa a che fare anche con il mio problema?

EDIT 2: Ho anche capito come sovrascrivere il metodo RegistrationsController#create di Devise, ma non so cosa mettere lì. L'intera cosa di Devise resource non ha senso per me, e sfogliare il loro codice sorgente per lo RegistrationsController non mi ha aiutato molto.

E per i punti bonus: Quando un utente invia il form di login con i dati non validi, il campo Locker torna sempre vuota, mentre i campi regolari concepire, nome utente & e-mail, vengono riempiti Questo potrebbe anche essere risolto facilmente. ? Se é cosi, come?

+0

come stai creando l'armadietto? Puoi pubblicare il codice del controller? – mihai

+0

Ho postato il mio Lockers # metodo di creazione, ma non penso che il mio codice stia arrivando anche a quello. Credo che Devise stia cercando di creare l'utente e di ignorare il mio codice del controller. Potrei sbagliarmi però. –

+1

che dovrebbe essere facile da controllare, basta aggiungere una riga 'debugger' nel controller e vedere se si ferma lì. – mihai

risposta

1

Qualcuno mi ha aiutato a capire la soluzione in modo più "Rails 4'y" via con strong attributes & come ignorare di Devise sign_up_params (per catturare tutti i dati provenienti dal mio modulo di iscrizione).

def sign_up_params 
    params.require(:user).permit(:username, :email, :password, :lockers_attributes) 
end 

Gemfile Inoltre: gem 'strong_parameters'

Commentando la dichiarazione attr_accessible nel mio file user.rb, dal momento che i parametri apparentemente forti eliminano la necessità di attr_accessible dichiarazioni.

# attr_accessible :username, :email, :password, :password_confirmation, :lockers 

E il/un corretto modo di costruire un armadietto prima di inviare il modulo: all'inizio del formato nidificato:

<%= l.input :name, :required => true, label: "Locker name", :placeholder => "Name your first locker" %>

Grazie ancora per il vostro aiuto. So che una domanda come questa è difficile da rispondere senza vedere l'intera base di codice.

1

prima, si dispone di un errore di battitura:

attr_accessible :locker_attributes 

dovrebbe essere plurale:

attr_accessible :lockers_attributes 

allora, il modo standard per utilizzare nested_attributes è:

<%= form_for @user do |f| %> 
    <%# fields_for will iterate over all user.lockers and 
     build fields for each one of them using the block below, 
     with html name attributes like user[lockers_attributes][0][name]. 
     it will also generate a hidden field user[lockers_attributes][0][id] 
     if the locker is already persisted, which allows nested_attributes 
     to know if the locker already exists of if it must create a new one 
    %> 
    <% f.fields_for :lockers do |locker_fields| %> 
    <%= locker_fields.label  :name %> 
    <%= locker_fields.text_field :name %> 
    <% end %> 
<% end %> 

e in voi regolatore :

def new 
    @user = User.new 
    @user.lockers.build 
end 

def create 
    # no need to use build here : params[:user] contains a 
    # :lockers_attributes key, which has an array of lockers attributes as value ; 
    # it gets assigned to the user using user.lockers_attributes=, 
    # a method created by nested_attributes 
    @user = User.new(params[:user]) 
end 

come nota a margine, si può evitare di costruire un nuovo spogliatoio per i nuovi utenti controller in modi diversi:

  • creare un metodo di fabbrica sul User, o ignorare new, o utilizzare un after_initialize callback per garantire ogni nuovo utente un'istanza ottiene un armadietto edificata automaticamente

  • passare un oggetto specifico per fields_for:

    <% f.fields_for :lockers, f.object.lockers.new do |new_locker_fields| %> 
    
+0

Apprezzo molto la tua risposta, e penso che tu sia sulla strada giusta (perché capisco dove stai andando con esso), ma l'errore di assegnazione di massa sta accadendo in Devise # create, e non ho idea di dove sia è. Posso già creare 'Utenti',' Lockers', ecc, è solo la nuova funzionalità di creare automaticamente un armadietto per l'utente al momento della registrazione non funziona. Sembra che ho bisogno di scavare in Devise, ma non so come. –

+0

oh, non ho capito che il problema era di Devise. Sapevi che puoi scavalcare i controller Devise? vedi [devise wiki] (https://github.com/plataformatec/devise#getting-started), sezione "configurare i controller" –

+1

oh, e il metodo che devi sovrascrivere è 'new_with_session' su' Utente'. C'è un [railscast] (http://railscasts.com/episodes/209-devise-revised?view=asciicast) a riguardo, ma sfortunatamente non è gratuito ... un'altra opzione è quella di sovrascrivere 'build_resource' sul controller. –