Diferença entre attr_accessor e attr_accessible

235

No Rails, qual é a diferença entre attr_accessore attr_accessible? Pelo meu entendimento, usar attr_accessoré usado para criar métodos getter e setter para essa variável, para que possamos acessar a variável como Object.variableou Object.variable = some_value.

Eu li que attr_accessibletorna essa variável específica acessível ao mundo exterior. Alguém pode me dizer qual é a diferença

felix
fonte
4
Você está certo attr_accessorao usar os métodos getter e setter. Por favor, veja minha resposta a uma pergunta anterior para obter uma explicação bastante abrangente de attr_accessible: stackoverflow.com/questions/2652907/…; em seguida, atualize sua pergunta se precisar de outros detalhes específicos depois disso.
MikeJ
2
attr_accessible não é mais suportado no Rails 4 a menos que você use a gema protected_attributes, conforme a resposta de cima para stackoverflow.com/questions/17371334/... (julho de 2014)
esmeril

Respostas:

258

attr_accessoré um método Ruby que cria um getter e um setter. attr_accessibleé um método Rails que permite passar valores para uma atribuição em massa: new(attrs)ou update_attributes(attrs).

Aqui está uma tarefa em massa:

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

Você pode imaginar que o pedido também pode ter um código de desconto, por exemplo :price_off. Se você não marcar :price_offcomo attr_accessibleimpedir que um código malicioso possa fazer o seguinte:

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

Mesmo que seu formulário não tenha um campo para :price_off, se estiver no seu modelo, ele estará disponível por padrão. Isso significa que um POST criado ainda pode defini-lo. O uso de attr_accessiblelistas brancas indica coisas que podem ser atribuídas em massa.

Paul Rubel
fonte
2
Por que não está attr_accessiblena documentação do Rails? api.rubyonrails.org
Chloe
19
Parece que o Rails4 tem uma nova maneira de fazer as coisas. Veja esta resposta: stackoverflow.com/questions/17371334/…
Paul Rubel 15/01
1
Como parâmetro forte substitui o uso de attr_accessible edgeguides.rubyonrails.org/…
Imran Ahmad
173

Muitas pessoas neste segmento e no google explicam muito bem que attr_accessibleespecifica uma lista de permissões de atributos que podem ser atualizados em massa ( todos os atributos de um modelo de objeto juntos ao mesmo tempo ) Isso é principalmente (e somente) para proteger seu aplicativo da exploração pirata "Atribuição em massa".

Isso é explicado aqui no documento oficial do Rails: Atribuição em massa

attr_accessoré um código ruby ​​para (rapidamente) criar métodos setter e getter em uma classe. Isso é tudo.

Agora, o que está faltando como explicação é que, quando você cria de alguma forma um link entre um modelo (Rails) com uma tabela de banco de dados, NUNCA, NUNCA NUNCA precisará NUNCA attr_accessorno seu modelo para criar setters e getters para poder modificar seu registros da tabela.

Isso ocorre porque seu modelo herda todos os métodos da ActiveRecord::Baseclasse, que já define acessadores CRUD básicos (criar, ler, atualizar, excluir) para você. Isso é explicado no documento oficial aqui Modelo do Rails e Substituindo o acessador padrão (role para baixo até o capítulo "Substituir o acessador padrão")

Digamos, por exemplo, que: temos uma tabela de banco de dados chamada "users" que contém três colunas "firstname", "lastname" e "role":

Instruções SQL:

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

Supus que você definisse a opção config.active_record.whitelist_attributes = trueem seu config / environment / production.rb para proteger seu aplicativo contra a exploração de atribuição em massa. Isso é explicado aqui: Atribuição em massa

Seu modelo Rails funcionará perfeitamente com o modelo aqui abaixo:

class User < ActiveRecord::Base

end

No entanto, você precisará atualizar cada atributo do usuário separadamente no seu controlador para que a Visualização do seu formulário funcione:

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

Agora, para facilitar sua vida, você não deseja criar um controlador complicado para o seu modelo de usuário. Então você usará o attr_accessiblemétodo especial no seu modelo de classe:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Então você pode usar a "rodovia" (atribuição em massa) para atualizar:

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

Você não adicionou os atributos "role" à attr_accessiblelista porque não permite que seus usuários definam suas funções por si mesmos (como administrador). Você mesmo faz isso em outra tela de administração especial.

Embora a visualização do usuário não mostre um campo "role", um pirata pode facilmente enviar uma solicitação HTTP POST que inclua "role" no hash de parâmetros. O atributo "role" ausente attr_accessibleé o de proteger seu aplicativo disso.

Você ainda pode modificar o atributo user.role por conta própria, como abaixo, mas não com todos os atributos juntos.

@user.role = DEFAULT_ROLE

Por que diabos você usaria o attr_accessor?

Bem, isso aconteceria se o formulário do usuário mostrar um campo que não existe na tabela de usuários como uma coluna.

Por exemplo, digamos que a visualização do usuário mostre um campo "informe o administrador que estou aqui". Você não deseja armazenar essas informações na sua tabela. Você só quer que o Rails envie um e-mail avisando que um usuário "louco" ;-) se inscreveu.

Para poder usar essas informações, você precisa armazená-las temporariamente em algum lugar. O que é mais fácil do que recuperá-lo em um user.peekabooatributo?

Então você adiciona este campo ao seu modelo:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Assim, você poderá fazer um uso instruído do user.peekaboo atributo em algum lugar do seu controlador para enviar um email ou fazer o que quiser.

O ActiveRecord não salvará o atributo "peekaboo" na sua tabela quando você fizer um, user.saveporque ela não vê nenhuma coluna correspondente a esse nome no modelo dela.

Douglas
fonte
48

attr_accessoré um método Ruby que fornece métodos setter e getter para uma variável de instância com o mesmo nome. Então é equivalente a

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

attr_accessible é um método Rails que determina quais variáveis ​​podem ser definidas em uma atribuição em massa.

Quando você envia um formulário e tem algo como MyModel.new params[:my_model] , deseja ter um pouco mais de controle, para que as pessoas não possam enviar coisas para as quais você não deseja.

Você pode fazer attr_accessible :emailisso quando alguém atualizar sua conta, alterar seu endereço de email. Mas você não faria isso attr_accessible :email, :salaryporque, em seguida, uma pessoa poderia definir seu salário através de um envio de formulário. Em outras palavras, eles poderiam abrir caminho para um aumento.

Esse tipo de informação precisa ser tratado explicitamente. Apenas removê-lo do formulário não é suficiente. Alguém poderia entrar com o firebug e adicionar o elemento ao formulário para enviar um campo de salário. Eles poderiam usar o curl embutido para enviar um novo salário ao método de atualização do controlador, eles poderiam criar um script que envia uma postagem com essas informações.

O mesmo attr_accessoracontece com a criação de métodos para armazenar variáveis ​​e attr_accessiblecom a segurança de atribuições em massa.

Joshua Cheek
fonte
2
Você tem um erro de digitação, depois que o bloco deve dizerattr_accesible
chubas
Ótimo escrever, eu gosto do exemplo da classe. Pontos de bônus extras (falsos) por incluir uma explicação sobre :as!
Ian Vaughan
O modelo é estendido pelo ActiveRecord :: Base. class User < ActiveRecord::Base
Verde
18

attr_accessoré um código ruby ​​e é usado quando você não possui uma coluna no banco de dados, mas ainda deseja mostrar um campo em seus formulários. A única maneira de permitir isso é attr_accessor :fieldnamee você pode usar esse campo na sua Visualização, ou modelo, se desejar, mas principalmente na sua Visualização.

Vamos considerar o seguinte exemplo

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

Aqui usamos attr_reader( atributo legível ) e attr_writer( atributo gravável ) para acessar a finalidade. Mas podemos alcançar a mesma funcionalidade usando attr_accessor. Em resumo, attr_accessor fornece acesso aos métodos getter e setter.

O código modificado é como abaixo

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

attr_accessiblepermite listar todas as colunas que você deseja permitir a atribuição em massa. O oposto disso é o attr_protectedque significa que este campo NÃO quero que ninguém seja autorizado a atribuir em massa a. É muito provável que seja um campo em seu banco de dados com o qual você não queira ninguém brincando. Como um campo de status ou semelhante.

shrikant1712
fonte
2
Então você está dizendo que, se eu criei campos em uma migração, disponibilize-os usando attr_accessible, não há necessidade de criar um getter e um setter? Mas se o campo não estiver no banco de dados, como o attr_accessible não age como um getter / setter? Se eu incluir uma linha "has_secure_password", o attr_accessible se tornará suficiente para permitir ao getter / setter: password e: password_confirmation mesmo que não estejam no banco de dados. Muito confuso;)
tentimes
2

Em duas palavras:

attr_accessoré getter, settermétodo. considerando attr_accessibleque esse atributo específico é acessível ou não. é isso aí.


Gostaria de acrescentar que devemos usar o parâmetro Strong em vez de attr_accessibleproteger da atribuição em massa.

Felicidades!

Manish Shrivastava
fonte
2

Uma visão geral rápida e concisa das diferenças:

attr_accessoré uma maneira fácil de criar acessadores de leitura e gravação em sua classe. É usado quando você não possui uma coluna no banco de dados, mas ainda deseja mostrar um campo em seus formulários. Este campo é um “virtual attribute” em um modelo Rails.

atributo virtual - um atributo que não corresponde a uma coluna no banco de dados.

attr_accessible é usado para identificar atributos acessíveis pelos métodos do controlador, disponibilizando uma propriedade para atribuição em massa. Isso permitirá apenas o acesso aos atributos que você especificar, negando o restante.

Muhammad Yawar Ali
fonte