Perché il attr_accessor clobber le variabili esistenti in questo modello in Ruby on Rails?
-
11-09-2019 - |
Domanda
Sono stato morso da questo di recente, e che sarebbe stato utile sapere esattamente cosa sta succedendo per rendere questo accada, in modo che altri evitare questo errore.
Ho un modello d'uso, con uno schema in questo modo:
create_table "users", :force => true do |t|
t.string "user_name"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "location"
t.string "town"
t.string "country"
t.string "postcode"
t.boolean "newsletter"
Nel user.rb di classe, ho un attr_accessor per tre metodi:
class User < ActiveRecord::Base
# lots of code
attr_protected :admin, :active
# relevant accessor methods
attr_accessor :town, :postcode, :country
end
Ora, nel mio controller utente, se ho il seguente metodo:
def create
@user = User.new params[:user]
end
Quando quando cerco di creare un nuovo utente con il contenuto in questo params hash:
--- !map:HashWithIndifferentAccess
# other values
country: United Kingdom
dob(1i): "1985"
dob(2i): "9"
dob(3i): "19"
town: london
L'oggetto restituito contiene stringhe vuote per i valori country
, town
e NPA postcode
, in questo modo.
(rdb:53) y user1
--- !ruby/object:User
attributes:
# lots of attributes that aren't relevant for this example, and are filled in okay
postcode:
country:
town:
Vi posso dire che i metodi attr_accessor sono clobbering metodi di accesso esistenti Active Record, perché quando li tiro fuori tutto funziona benissimo, quindi la soluzione è abbastanza semplice -. Basta portarli fuori
Ma cosa esattamente sta succedendo quando qui?
sto cercando qui in rotaie documentazione API per Active Record , e qui in propri documenti di Ruby su attr_accessor
, ma io sono ancora un po 'confusa su come attr_accessor
sta rompendo le cose qui
Qualsiasi in grado di far luce per fermare qualche altra povera anima di infrangere questo?
Soluzione
Quando si aggiunge un attr_accessor ad una classe, definisce due metodi su di esso, ad esempio, Utente # codice postale e l'utente # Cap =.
Se il nome della funzione di accesso è pari a un nome di un attributo di modello, le cose si rompono (se non stai attento). Quando si assegna attributi al modello, l'utente # Cap = si chiama e nel tuo caso non si fa nulla, tranne
@postcode = value
Quindi il valore appena viene memorizzato in una variabile di istanza e non appare nella attributi hash.
considerando che in uno scenario normale (senza una funzione di accesso) questo sarebbe andato a method_missing ed eventualmente innescare qualcosa di simile
write_attribute(:postcode, value)
E poi sembrerebbe negli attributi del vostro modello. Spero che abbia un senso.
Altri suggerimenti
Perché in primo luogo che si sta utilizzando attr_accessor :town, :postcode, :country
? Attivo Record ha metodi setter / getter per voi. Basta inserire quella linea, le cose dovrebbero funzionare.
Si potrebbe desiderare di utilizzare attr_accessible
su modelli ActiveRecord per consentire di massa-assegnazione di attributi. Non è necessario attr_accessor
come getter / setter sono già definiti per gli attributi del modello.