Differenza tra attr_accessor e attr_accessible


235

In Rails, qual è la differenza tra attr_accessore attr_accessible? Secondo la mia comprensione, l'utilizzo attr_accessorviene utilizzato per creare metodi getter e setter per quella variabile, in modo che possiamo accedere alla variabile come Object.variableo Object.variable = some_value.

Ho letto che attr_accessiblerende quella specifica variabile accessibile al mondo esterno. Qualcuno può dirmi qual è la differenza


4
Hai ragione che attr_accessorviene utilizzato per generare metodi getter e setter. Si prega di consultare la mia risposta a una domanda precedente per una spiegazione piuttosto esauriente di attr_accessible: stackoverflow.com/questions/2652907/…, quindi aggiornare la domanda se sono necessari altri dettagli specifici successivamente.
mikej,

2
attr_accessible non è più supportato in Rails 4 a meno che tu non usi la gemma protetta_attributo, come da risposta principale a stackoverflow.com/questions/17371334/… (luglio 2014)
emery

Risposte:


258

attr_accessorè un metodo Ruby che rende un getter e un setter. attr_accessibleè un metodo Rails che ti consente di trasferire valori a un'assegnazione di massa: new(attrs)o update_attributes(attrs).

Ecco un incarico di massa:

Order.new({ :type => 'Corn', :quantity => 6 })

Puoi immaginare che l'ordine potrebbe anche avere un codice di sconto, diciamo :price_off. Se non tagghi :price_offmentre attr_accessibleimpedisci al codice dannoso di poter fare così:

Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })

Anche se il modulo non ha un campo per :price_off, se è nel modello è disponibile per impostazione predefinita. Ciò significa che un POST predisposto potrebbe ancora impostarlo. L'uso di attr_accessiblewhite list elenca le cose che è possibile assegnare in massa.


2
Perché non è attr_accessiblenella documentazione di Rails? api.rubyonrails.org
Chloe,

19
Sembra che Rails4 abbia un nuovo modo di fare le cose. Vedi questa risposta: stackoverflow.com/questions/17371334/…
Paul Rubel,

1
Perché parametro forte ha sostituito l'uso di attr_accessible edgeguides.rubyonrails.org/…
Imran Ahmad,

173

Molte persone su questo thread e su Google spiegano molto bene che attr_accessiblespecifica una whitelist di attributi che possono essere aggiornati in blocco ( tutti gli attributi di un modello a oggetti contemporaneamente ) Questo è principalmente (e solo) per proteggere la tua applicazione dall'exploit pirata "Assegnazione di massa".

Questo è spiegato qui nel documento ufficiale di Rails: Assegnazione di massa

attr_accessorè un codice rubino per (rapidamente) creare metodi setter e getter in una classe. È tutto.

Ora, ciò che manca come spiegazione è che quando crei in qualche modo un collegamento tra un modello (Rails) con una tabella di database, non hai MAI, MAI MAI, MAI PIÙ bisogno attr_accessornel tuo modello di creare setter e getter per poter modificare il tuo record della tabella.

Questo perché il tuo modello eredita tutti i metodi dalla ActiveRecord::BaseClasse, che definisce già per te gli accessi CRUD di base (Crea, Leggi, Aggiorna, Elimina). Questo è spiegato nel documento ufficiale qui Rails Model e qui Sovrascrivi accessor predefinito (scorri verso il basso fino al capitolo "Sovrascrivi accessor predefinito")

Supponiamo ad esempio che: abbiamo una tabella di database chiamata "utenti" che contiene tre colonne "nome", "cognome" e "ruolo":

Istruzioni SQL:

CREATE TABLE users (
  firstname string,
  lastname string
  role string
);

Presumo che tu abbia impostato l'opzione config.active_record.whitelist_attributes = truein config / environment / production.rb per proteggere la tua applicazione dall'exploit di assegnazione di massa. Questo è spiegato qui: Assegnazione di massa

Il tuo modello Rails funzionerà perfettamente con il modello qui sotto:

class User < ActiveRecord::Base

end

Tuttavia, sarà necessario aggiornare ogni attributo dell'utente separatamente nel controller affinché la vista del modulo funzioni:

def update
    @user = User.find_by_id(params[:id])
    @user.firstname = params[:user][:firstname]
    @user.lastname = params[:user][:lastname]

    if @user.save
        # Use of I18 internationalization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

Ora, per semplificarti la vita, non vuoi creare un controller complicato per il tuo modello utente. Quindi utilizzerai il attr_accessiblemetodo speciale nel tuo modello di classe:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Quindi puoi usare l '"autostrada" (assegnazione di massa) per aggiornare:

def update
    @user = User.find_by_id(params[:id])

    if @user.update_attributes(params[:user])
        # Use of I18 internationlization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

Non hai aggiunto gli attributi "ruolo" attr_accessibleall'elenco perché non permetti ai tuoi utenti di impostare il loro ruolo da soli (come l'amministratore). Puoi farlo tu stesso su un'altra vista amministratore speciale.

Sebbene la vista dell'utente non mostri un campo "ruolo", un pirata potrebbe facilmente inviare una richiesta POST HTTP che includa "ruolo" nell'hash dei parametri. L'attributo "ruolo" mancante su attr_accessibleè per proteggere l'applicazione da quello.

Puoi comunque modificare l'attributo user.role da solo come di seguito, ma non con tutti gli attributi insieme.

@user.role = DEFAULT_ROLE

Perché diavolo dovresti usare il attr_accessor?

Bene, questo sarebbe nel caso in cui il modulo utente mostri un campo che non esiste nella tabella degli utenti come colonna.

Ad esempio, supponiamo che la vista dell'utente mostri un campo "per favore, dì all'amministratore che sono qui". Non vuoi memorizzare queste informazioni nella tua tabella. Vuoi solo che Rails ti invii un'e-mail che ti avverta che un utente "pazzo" ;-) si è iscritto.

Per poter utilizzare queste informazioni è necessario memorizzarle temporaneamente da qualche parte. Cosa c'è di più facile che recuperarlo in un user.peekabooattributo?

Quindi aggiungi questo campo al tuo modello:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Quindi sarai in grado di fare un uso user.peekabooconsapevole dell'attributo da qualche parte nel tuo controller per inviare una e-mail o fare quello che vuoi.

ActiveRecord non salverà l'attributo "peekaboo" nella tabella quando lo fai user.saveperché non vede alcuna colonna corrispondente a questo nome nel suo modello.


48

attr_accessorè un metodo Ruby che offre metodi setter e getter a una variabile di istanza con lo stesso nome. Quindi è equivalente a

class MyModel
  def my_variable
    @my_variable
  end
  def my_variable=(value)
    @my_variable = value
  end
end

attr_accessible è un metodo Rails che determina quali variabili possono essere impostate in un'assegnazione di massa.

Quando invii un modulo e hai qualcosa del genere MyModel.new params[:my_model], vuoi avere un po 'più di controllo, in modo che le persone non possano inviare cose che non desideri.

Si potrebbe fare in attr_accessible :emailmodo che quando qualcuno aggiorna il proprio account, possa cambiare il proprio indirizzo e-mail. Ma non lo faresti attr_accessible :email, :salaryperché una persona potrebbe fissare il proprio stipendio tramite l'invio di un modulo. In altre parole, potrebbero hackerare la strada per un rilancio.

Questo tipo di informazioni deve essere gestito in modo esplicito. Basta rimuoverlo dal modulo non è sufficiente. Qualcuno potrebbe entrare con firebug e aggiungere l'elemento nel modulo per inviare un campo di stipendio. Potrebbero utilizzare il ricciolo integrato per inviare un nuovo stipendio al metodo di aggiornamento del controller, potrebbero creare uno script che invia un post con tali informazioni.

Lo stesso attr_accessorvale per la creazione di metodi per memorizzare variabili e attr_accessibleper la sicurezza delle assegnazioni di massa.


2
Hai un refuso, dopo il blocco di codice dovrebbe direattr_accesible
Chubas

Ottima scrittura, mi piace l'esempio di classe. Punti bonus (falsi) extra per l'inclusione di una spiegazione di :as!
Ian Vaughan,

Il modello è esteso da ActiveRecord :: Base. class User < ActiveRecord::Base
Verde,

18

attr_accessorè un codice ruby ​​e viene utilizzato quando non si dispone di una colonna nel database, ma si desidera comunque mostrare un campo nei moduli. L'unico modo per permetterlo è attr_accessor :fieldnamee puoi usare questo campo nella tua vista, o modello, se lo desideri, ma principalmente nella tua vista.

Consideriamo il seguente esempio

class Address
    attr_reader :street
    attr_writer :street  
    def initialize
        @street = ""
    end
end

Qui abbiamo usato attr_reader( attributo leggibile ) e attr_writer( attributo scrivibile ) a scopo di accesso. Ma possiamo ottenere la stessa funzionalità usando attr_accessor. In breve, attr_accessor fornisce l'accesso a entrambi i metodi getter e setter.

Quindi il codice modificato è come di seguito

class Address
    attr_accessor :street  
    def initialize
        @street = ""
    end
end

attr_accessibleconsente di elencare tutte le colonne che si desidera consentire Assegnazione di massa. L'opposto di questo è attr_protectedche significa che questo campo NON voglio che a nessuno sia permesso di assegnare in massa. Molto probabilmente sarà un campo nel tuo database con il quale non vuoi che nessuno si occupi del monkeking. Come un campo di stato o simili.


2
Quindi stai dicendo che se ho creato campi in una migrazione, quindi li rendo disponibili usando attr_accessible, non è necessario creare un getter e setter? Ma se il campo non è nel database, come mai attr_accessible non si comporta come un getter / setter? Se includo una riga "has_secure_password", attr_accessible diventa sufficiente per consentire a getter / setter di: password e: password_confirmation anche se non si trovano nel database. Molto confuso;)
tentimes

2

In due parole:

attr_accessorè getter, settermetodo. considerando attr_accessibleche questo particolare attributo è accessibile o meno. questo è tutto.


Vorrei aggiungere che dovremmo usare il parametro Strong invece diattr_accessible proteggere dalle assegnazioni di massa.

Saluti!


2

Una panoramica delle differenze rapida e concisa:

attr_accessorè un modo semplice per creare accessori di lettura e scrittura nella tua classe. Viene utilizzato quando non si dispone di una colonna nel database, ma si desidera comunque mostrare un campo nei moduli. Questo campo è un “virtual attribute”modello in Rails.

attributo virtuale : un attributo non corrispondente a una colonna nel database.

attr_accessible viene utilizzato per identificare gli attributi accessibili dai metodi del controller e rende disponibile una proprietà per l'assegnazione di massa. Consentirà solo l'accesso agli attributi specificati, negando il resto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.