Różnica między attr_accessor i attr_accessible

235

W Railsach jaka jest różnica między attr_accessori attr_accessible? Z mojego rozumienia, przy użyciu attr_accessorużywa się do tworzenia metod pobierających i ustawiających dla tej zmiennej, abyśmy mogli uzyskać dostęp do zmiennej jak Object.variablelub Object.variable = some_value.

Przeczytałem, attr_accessibleże ta konkretna zmienna jest dostępna dla świata zewnętrznego. Czy ktoś może mi powiedzieć, jaka jest różnica

Felix
źródło
4
Masz rację, który attr_accessorjest używany do generowania metod pobierających i ustawiających. Zapoznaj się z moją odpowiedzią na poprzednie pytanie, aby uzyskać dość wyczerpujące wyjaśnienie attr_accessible: stackoverflow.com/questions/2652907/…, a następnie zaktualizuj swoje pytanie, jeśli potrzebujesz później innych szczegółowych informacji.
mikej
2
attr_accessible nie jest już obsługiwany w Railsach 4, chyba że użyjesz gemu chronionych atrybutów, zgodnie z najlepszą odpowiedzią na stackoverflow.com/questions/17371334/... (lipiec 2014 r.)
szmergiel 12'14

Odpowiedzi:

258

attr_accessorjest metodą Ruby, która tworzy gettera i setera. attr_accessiblejest metodą Railsową, która pozwala przekazać wartości do przypisania masy: new(attrs)lub update_attributes(attrs).

Oto zadanie masowe:

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

Można sobie wyobrazić, że zamówienie może zawierać kod rabatowy, powiedzmy :price_off. Jeśli nie oznaczysz tagiem, :price_offponieważ attr_accessiblepowstrzymujesz złośliwy kod przed zrobieniem tego:

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

Nawet jeśli twój formularz nie ma pola :price_off, jeśli jest w twoim modelu, jest domyślnie dostępny. Oznacza to, że spreparowany test POST mógłby go nadal ustawić. Użycie attr_accessiblebiałej listy zawiera te rzeczy, które można przypisać masowo.

Paul Rubel
źródło
2
Dlaczego nie ma attr_accessiblew dokumentacji Railsów? api.rubyonrails.org
Chloe
19
Wygląda na to, że Rails4 ma nowy sposób robienia rzeczy. Zobacz tę odpowiedź: stackoverflow.com/questions/17371334/...
Paul Rubel
1
Ponieważ silny parametr zastąpił użycie attr_accessible edgeguides.rubyonrails.org/…
Imran Ahmad
173

Wiele osób w tym wątku i w Google bardzo dobrze wyjaśnia, które attr_accessibleokreśla białą listę atrybutów, które mogą być aktualizowane zbiorczo ( wszystkie atrybuty modelu obiektowego jednocześnie ). Ma to głównie (i tylko) na celu ochronę twojej aplikacji z exploitu pirackiego „Mass Assignment”.

Jest to wyjaśnione tutaj w oficjalnym dokumencie Rails: Mass Assignment

attr_accessorto ruby ​​kod do (szybkiego) tworzenia metod ustawiających i pobierających w klasie. To wszystko.

Wyjaśnieniem jest to, że kiedy w jakiś sposób tworzysz połączenie między modelem (Rails) z tabelą bazy danych, NIGDY, NIGDY, NIGDY nie potrzebujesz attr_accessorw swoim modelu, aby tworzyć setery i gettery, aby móc modyfikować swój rekordy tabeli.

Wynika to z faktu, że Twój model dziedziczy wszystkie metody z ActiveRecord::Baseklasy, która już definiuje podstawowe akcesoria CRUD (tworzenie, czytanie, aktualizacja, usuwanie). Jest to wyjaśnione w oficjalnym dokumencie tutaj Rails Model i tutaj Nadpisywanie domyślnego akcesorium (przewiń w dół do rozdziału „Nadpisz domyślnego akcesorium”)

Powiedz na przykład, że: mamy tabelę bazy danych o nazwie „użytkownicy”, która zawiera trzy kolumny „imię”, „nazwisko” i „rola”:

Instrukcje SQL:

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

Zakładałem, że ustawiłeś opcję config.active_record.whitelist_attributes = truew config / environment / production.rb, aby chronić swoją aplikację przed exploitem Mass Assignment. Wyjaśniono to tutaj: Przydział masowy

Twój model Rails będzie idealnie współpracował z poniższym modelem:

class User < ActiveRecord::Base

end

Musisz jednak zaktualizować każdy atrybut użytkownika osobno w kontrolerze, aby widok formularza działał:

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

Teraz, aby ułatwić ci życie, nie chcesz tworzyć skomplikowanego kontrolera dla swojego modelu użytkownika. Więc zastosujesz attr_accessiblespecjalną metodę w swoim modelu klasy:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Możesz więc użyć „autostrady” (przypisanie masowe) do aktualizacji:

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

Nie dodałeś atrybutów „rola” do attr_accessiblelisty, ponieważ nie pozwalasz użytkownikom na samodzielne ustawianie swojej roli (np. Admin). Robisz to sam na innym specjalnym widoku administratora.

Chociaż twój widok użytkownika nie pokazuje pola „rola”, pirat może z łatwością wysłać żądanie HTTP POST zawierające „rolę” w haszowaniu parametrów. Brak atrybutu „rola” attr_accessiblesłuży do ochrony aplikacji przed tym.

Nadal możesz samodzielnie modyfikować atrybut user.role, jak poniżej, ale nie wszystkie atrybuty razem.

@user.role = DEFAULT_ROLE

Dlaczego, do diabła, miałbyś skorzystać attr_accessor?

Tak byłoby w przypadku, gdy formularz użytkownika pokazuje pole, które nie istnieje w tabeli użytkowników jako kolumna.

Załóżmy na przykład, że Twój widok użytkownika pokazuje pole „proszę powiedzieć administratorowi, że jestem tutaj”. Nie chcesz przechowywać tych informacji w swoim stole. Chcesz, aby Railsy wysłały Ci wiadomość e-mail z ostrzeżeniem, że jeden „szalony” ;-) użytkownik zasubskrybował.

Aby móc skorzystać z tych informacji, musisz je gdzieś tymczasowo przechowywać. Czy jest coś łatwiejszego niż odzyskanie go w user.peekabooatrybucie?

Więc dodajesz to pole do swojego modelu:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Dzięki temu będziesz mógł w przemyślany sposób wykorzystać ten user.peekabooatrybut gdzieś w kontrolerze, aby wysłać wiadomość e-mail lub zrobić co chcesz.

ActiveRecord nie zapisze atrybutu „peekaboo” w twojej tabeli, kiedy to zrobisz, user.saveponieważ nie widzi żadnej kolumny pasującej do tej nazwy w swoim modelu.

Douglas
źródło
48

attr_accessorjest metodą Ruby, która daje metody ustawiające i pobierające do zmiennej instancji o tej samej nazwie. Jest to więc równoważne z

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

attr_accessible jest metodą Railsową, która określa, jakie zmienne można ustawić w przypisaniu masy.

Po przesłaniu formularza masz coś takiego MyModel.new params[:my_model] , chcesz mieć trochę więcej kontroli, aby ludzie nie mogli przesyłać rzeczy, których nie chcesz.

Możesz to zrobić attr_accessible :email, gdy ktoś zaktualizuje swoje konto, może zmienić swój adres e-mail. Ale nie zrobiłbyś tego, attr_accessible :email, :salaryponieważ wtedy osoba mogłaby ustalić swoje wynagrodzenie poprzez złożenie formularza. Innymi słowy, mogliby włamać się do podwyżki.

Tego rodzaju informacje wymagają jawnego przetwarzania. Samo usunięcie go z formularza nie wystarczy. Ktoś może wejść z firebugiem i dodać element do formularza, aby przesłać pole wynagrodzenia. Mogą użyć wbudowanego curl, aby przesłać nową pensję do metody aktualizacji kontrolera, mogą stworzyć skrypt, który przesyła post z tymi informacjami.

Podobnie attr_accessorjest z tworzeniem metod przechowywania zmiennych, a także attr_accessiblez bezpieczeństwem przypisań masowych.

Joshua Cheek
źródło
2
Masz literówkę, po bloku kodu powinien być attr_accesible
napisany
Świetnie napisz, podoba mi się przykład klasy. Dodatkowe (fałszywe) punkty bonusowe za wyjaśnienie :as!
Ian Vaughan,
Model został rozszerzony o ActiveRecord :: Base. class User < ActiveRecord::Base
Zielony,
18

attr_accessorjest kodem ruby ​​i jest używany, gdy nie masz kolumny w bazie danych, ale nadal chcesz pokazać pole w swoich formularzach. Jedynym sposobem na to jest to attr_accessor :fieldnamei możesz użyć tego pola w widoku lub modelu, jeśli chcesz, ale głównie w widoku.

Rozważmy następujący przykład

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

Tutaj użyliśmy attr_reader( atrybut czytelny ) i attr_writer( atrybut zapisywalny ) w celu uzyskania dostępu do celu. Ale możemy osiągnąć tę samą funkcjonalność za pomocą attr_accessor. W skrócie, attr_accessor zapewnia dostęp zarówno do metod pobierających, jak i ustawiających.

Tak zmodyfikowany kod jest jak poniżej

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

attr_accessiblepozwala wyświetlić listę wszystkich kolumn, które chcesz zezwolić na Przypisanie masowe. Przeciwnie do tego, attr_protectedco oznacza, że ​​to pole NIE chcę, aby ktokolwiek miał pozwolenie na Mass Assign. Jest bardziej niż prawdopodobne, że będzie to pole w Twojej bazie danych, z którym nie chcesz, aby ktokolwiek małpował. Jak pole statusu lub tym podobne.

shrikant1712
źródło
2
Mówisz więc, że jeśli utworzyłem pola podczas migracji, a następnie udostępnię je za pomocą attr_accessible, nie ma potrzeby tworzenia gettera i settera? Ale jeśli pola nie ma w bazie danych, dlaczego attr_accessible nie działa jak getter / setter? Jeśli dołączę wiersz „has_secure_password”, attr_accessible staje się wystarczający, aby pozwolić getter / setter na: hasło i: potwierdzenie_hasła, nawet jeśli nie ma ich w bazie danych. Bardzo zdezorientowany;)
tentimes
2

W dwóch słowach:

attr_accessorjest getter, settermetody. mając na uwadze attr_accessible, że konkretny atrybut jest dostępny lub nie. Otóż ​​to.


Chciałbym dodać, że powinniśmy użyć parametru Strong zamiast attr_accessiblechronić przed przypisaniem masy.

Twoje zdrowie!

Manish Shrivastava
źródło
2

Szybki i zwięzły przegląd różnic:

attr_accessorto prosty sposób na tworzenie akcesoriów do odczytu i zapisu w klasie. Jest używany, gdy nie masz kolumny w bazie danych, ale nadal chcesz pokazać pole w formularzach. To pole jest “virtual attribute”w modelu Railsowym.

atrybut wirtualny - atrybut niezgodny z kolumną w bazie danych.

attr_accessible służy do identyfikowania atrybutów, które są dostępne za pomocą metod kontrolera, udostępnia właściwość do przypisania masowego. Umożliwi to dostęp tylko do określonych atrybutów, odmawiając reszty.

Muhammad Yawar Ali
źródło