Unterschied zwischen attr_accessor und attr_accessible


235

Was ist in Rails der Unterschied zwischen attr_accessorund attr_accessible? Nach meinem Verständnis wird using attr_accessorverwendet, um Getter- und Setter-Methoden für diese Variable zu erstellen, damit wir auf die Variable wie Object.variableoder zugreifen können Object.variable = some_value.

Ich habe gelesen, attr_accessibledass diese spezifische Variable für die Außenwelt zugänglich ist. Kann mir bitte jemand sagen, was der Unterschied ist


4
Sie haben Recht, das attr_accessorwird verwendet, um Getter- und Setter-Methoden zu generieren. In meiner Antwort auf eine vorherige Frage finden Sie eine ziemlich umfassende Erklärung zu attr_accessible: stackoverflow.com/questions/2652907/…. Aktualisieren Sie dann Ihre Frage, wenn Sie danach weitere spezifische Details benötigen.
Mikej

2
attr_accessible wird nicht mehr unterstützt in Rails 4 , wenn Sie den protected_attributes gem verwenden, wie pro oben Antwort auf stackoverflow.com/questions/17371334/... (Juli 2014)
Schmirgel

Antworten:


258

attr_accessorist eine Ruby-Methode, die einen Getter und einen Setter macht. attr_accessibleist eine Rails-Methode, mit der Sie Werte an eine Massenzuweisung übergeben können: new(attrs)oder update_attributes(attrs).

Hier ist eine Massenaufgabe:

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

Sie können sich vorstellen, dass die Bestellung beispielsweise auch einen Rabattcode enthält :price_off. Wenn Sie nicht markieren, :price_offwährend attr_accessibleSie verhindern, dass bösartiger Code dies tun kann:

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

Auch wenn Ihr Formular kein Feld für enthält :price_off, ist es in Ihrem Modell standardmäßig verfügbar. Dies bedeutet, dass ein gestalteter POST ihn immer noch einstellen kann. Durch die Verwendung von attr_accessibleweißen Listen werden die Dinge aufgelistet, die massenweise zugewiesen werden können.


2
Warum ist nicht attr_accessiblein der Rails-Dokumentation? api.rubyonrails.org
Chloe

19
Es sieht so aus, als hätte Rails4 eine neue Art, Dinge zu tun. Siehe diese Antwort: stackoverflow.com/questions/17371334/…
Paul Rubel

1
Weil starke Parameter die Verwendung von attr_accessible edgeguides.rubyonrails.org/…
Imran Ahmad

173

Viele Leute in diesem Thread und bei Google erklären sehr gut, dass attr_accessibleeine Whitelist von Attributen angegeben ist, die in großen Mengen aktualisiert werden dürfen ( alle Attribute eines Objektmodells gleichzeitig ). Dies dient hauptsächlich (und nur) dem Schutz Ihrer Anwendung aus "Massenauftrag" Piraten Exploit.

Dies wird hier im offiziellen Rails-Dokument: Massenzuweisung erläutert

attr_accessorist ein Ruby-Code zum (schnellen) Erstellen von Setter- und Getter-Methoden in einer Klasse. Das ist alles.

Als Erklärung fehlt nun, dass Sie beim Erstellen einer Verknüpfung zwischen einem (Rails-) Modell und einer Datenbanktabelle NIEMALS, NIEMALS, NIEMALS attr_accessorin Ihrem Modell Setter und Getter erstellen müssen, um Ihre zu ändern Tabellenaufzeichnungen.

Dies liegt daran, dass Ihr Modell alle Methoden von der ActiveRecord::BaseKlasse erbt , die bereits grundlegende CRUD-Accessoren (Erstellen, Lesen, Aktualisieren, Löschen) für Sie definiert. Dies wird im offiziellen Dokument hier Rails Model und hier Überschreiben des Standard-Accessors erläutert (scrollen Sie nach unten zum Kapitel "Standard-Accessor überschreiben").

Sagen Sie zum Beispiel: Wir haben eine Datenbanktabelle namens "Benutzer", die drei Spalten "Vorname", "Nachname" und "Rolle" enthält:

SQL-Anweisungen:

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

Ich ging davon aus, dass Sie die Option config.active_record.whitelist_attributes = truein Ihrer config / environment / Production.rb festgelegt haben, um Ihre Anwendung vor dem Exploit der Massenzuweisung zu schützen. Dies wird hier erklärt: Massenzuordnung

Ihr Rails-Modell funktioniert perfekt mit dem folgenden Modell:

class User < ActiveRecord::Base

end

Sie müssen jedoch jedes Benutzerattribut in Ihrem Controller separat aktualisieren, damit die Ansicht Ihres Formulars funktioniert:

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

Um Ihnen das Leben zu erleichtern, möchten Sie keinen komplizierten Controller für Ihr Benutzermodell erstellen. Sie verwenden also die attr_accessiblespezielle Methode in Ihrem Klassenmodell:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Sie können also die "Autobahn" (Massenzuweisung) verwenden, um Folgendes zu aktualisieren:

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

Sie haben die "Rollen" -Attribute nicht zur attr_accessibleListe hinzugefügt, weil Sie nicht zulassen, dass Ihre Benutzer ihre Rolle selbst festlegen (wie z. B. admin). Sie tun dies selbst in einer anderen speziellen Administratoransicht.

Obwohl in Ihrer Benutzeransicht kein "Rollen" -Feld angezeigt wird, kann ein Pirat leicht eine HTTP-POST-Anforderung senden, die "Rolle" im Parameter-Hash enthält. Das fehlende "Rollen" -Attribut auf attr_accessiblesoll Ihre Anwendung davor schützen.

Sie können Ihr user.role-Attribut weiterhin wie unten beschrieben ändern, jedoch nicht mit allen Attributen zusammen.

@user.role = DEFAULT_ROLE

Warum zum Teufel würdest du das benutzen attr_accessor?

Nun, dies wäre der Fall, wenn Ihr Benutzerformular ein Feld, das in Ihrer Benutzertabelle nicht vorhanden ist, als Spalte anzeigt.

Angenommen, in Ihrer Benutzeransicht wird das Feld "Bitte sagen Sie dem Administrator, dass ich hier bin" angezeigt. Sie möchten diese Informationen nicht in Ihrer Tabelle speichern. Sie möchten nur, dass Rails Ihnen eine E-Mail sendet, in der Sie gewarnt werden, dass ein "verrückter" ;-) Benutzer sich angemeldet hat.

Um diese Informationen nutzen zu können, müssen Sie sie vorübergehend irgendwo speichern. Was ist einfacher, als es in einem user.peekabooAttribut wiederherzustellen ?

Also fügen Sie dieses Feld Ihrem Modell hinzu:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

So können Sie das user.peekabooAttribut irgendwo in Ihrem Controller gründlich nutzen , um eine E-Mail zu senden oder zu tun, was Sie wollen.

ActiveRecord speichert das Attribut "peekaboo" nicht in Ihrer Tabelle, wenn Sie eine ausführen, user.saveda in ihrem Modell keine Spalte angezeigt wird, die diesem Namen entspricht.


48

attr_accessorist eine Ruby-Methode, mit der Sie Setter- und Getter-Methoden für eine gleichnamige Instanzvariable verwenden können. Es ist also gleichbedeutend mit

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

attr_accessible ist eine Rails-Methode, die bestimmt, welche Variablen in einer Massenzuweisung festgelegt werden können.

Wenn Sie ein Formular einreichen und so etwas haben, MyModel.new params[:my_model]möchten Sie ein bisschen mehr Kontrolle haben, damit die Leute keine Dinge einreichen können, die Sie nicht möchten.

Sie können dies tun, attr_accessible :emaildamit jemand, der sein Konto aktualisiert, seine E-Mail-Adresse ändern kann. Aber Sie würden es nicht tun, attr_accessible :email, :salaryweil dann eine Person ihr Gehalt durch eine Formularübermittlung festlegen könnte. Mit anderen Worten, sie könnten sich den Weg zu einer Gehaltserhöhung bahnen.

Diese Art von Informationen muss explizit behandelt werden. Es reicht nicht aus, es nur aus dem Formular zu entfernen. Jemand könnte mit Firebug hineingehen und das Element in das Formular einfügen, um ein Gehaltsfeld einzureichen. Sie könnten die eingebaute Locke verwenden, um ein neues Gehalt an die Controller-Aktualisierungsmethode zu senden. Sie könnten ein Skript erstellen, das einen Beitrag mit diesen Informationen sendet.

Es geht also attr_accessordarum, Methoden zum Speichern von Variablen zu erstellen, und es attr_accessiblegeht um die Sicherheit von Massenzuweisungen.


2
Sie haben einen Tippfehler, nach dem Codeblock sollte es attr_accesible
heißen

Tolles Schreiben, ich mag das Klassenbeispiel. Zusätzliche (gefälschte) Bonuspunkte für eine Erklärung von :as!
Ian Vaughan

Das Modell wird um ActiveRecord :: Base erweitert. class User < ActiveRecord::Base
Green

18

attr_accessorist Ruby-Code und wird verwendet, wenn Sie keine Spalte in Ihrer Datenbank haben, aber dennoch ein Feld in Ihren Formularen anzeigen möchten. Die einzige Möglichkeit, dies zuzulassen, besteht darin attr_accessor :fieldname, dieses Feld in Ihrer Ansicht oder Ihrem Modell zu verwenden, wenn Sie dies wünschen, jedoch hauptsächlich in Ihrer Ansicht.

Betrachten wir das folgende Beispiel

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

Hier haben wir attr_reader( lesbares Attribut ) und attr_writer( beschreibbares Attribut ) für den Zugriff verwendet. Aber wir können die gleiche Funktionalität mit erreichen attr_accessor. Kurz gesagt, attr_accessor bietet Zugriff auf Getter- und Setter-Methoden.

Der geänderte Code ist also wie folgt

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

attr_accessibleMit dieser Option können Sie alle Spalten auflisten, für die Sie die Massenzuweisung zulassen möchten. Das Gegenteil davon ist, attr_protectedwas bedeutet, dass ich in diesem Feld NICHT möchte, dass jemand eine Massenzuweisung erhält. Höchstwahrscheinlich wird es sich um ein Feld in Ihrer Datenbank handeln, mit dem niemand herumspielen soll. Wie ein Statusfeld oder ähnliches.


2
Wollen Sie damit sagen, dass Sie, wenn ich Felder in einer Migration erstellt habe und diese dann mit attr_accessible verfügbar mache, keinen Getter und Setter erstellen müssen? Aber wenn sich das Feld nicht in der Datenbank befindet, wie kommt es, dass attr_accessible nicht wie ein Getter / Setter wirkt? Wenn ich eine Zeile "has_secure_password" einfüge, reicht attr_accessible aus, um Getter / Setter zu erlauben: password und: password_confirmation, obwohl sie nicht in der Datenbank sind. Sehr verwirrt;)
Zeltzeit


2

Eine schnelle und übersichtliche Übersicht über die Unterschiede:

attr_accessorist eine einfache Möglichkeit, Lese- und Schreibzugriffe in Ihrer Klasse zu erstellen. Es wird verwendet, wenn Sie keine Spalte in Ihrer Datenbank haben, aber dennoch ein Feld in Ihren Formularen anzeigen möchten. Dieses Feld befindet sich “virtual attribute”in einem Rails-Modell.

virtuelles Attribut - Ein Attribut, das keiner Spalte in der Datenbank entspricht.

attr_accessible wird verwendet, um Attribute zu identifizieren, auf die Ihre Controller-Methoden zugreifen können, und stellt eine Eigenschaft für die Massenzuweisung zur Verfügung. Sie ermöglicht nur den Zugriff auf die von Ihnen angegebenen Attribute und verweigert den Rest.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.