ActionController::Parameters#with_defaults fornece valores para chaves que não chegaram na requisição. É um alias para reverse_merge, então o hash que você passa perde para qualquer coisa que o navegador tenha enviado.
Ele se justifica porque o navegador não envia absolutamente nada em vários casos comuns. Um controller que trata “ausente” e “false” de formas diferentes erra nesses casos.
O que este tutorial aborda
- Fornecer valores padrão para parâmetros que o navegador pode omitir.
- Como as checkboxes do Rails já resolvem isso com um campo oculto.
- Por que um valor padrão não é um mecanismo de autorização.
Requisitos
Fornecendo um valor padrão
status chegar, ele é usado. Se não chegar, "draft" é usado. Checkboxes desmarcadas e campos de seleção múltipla não selecionados são o motivo usual para uma chave estar ausente. Um valor padrão é mais organizado do que uma cadeia de condicionais na action.
ActionController::Parameters não é um Hash, embora se esforce para se comportar como um. Ele implementa merge, values_at, compact, blank? e uma longa lista de outros métodos. with_defaults faz parte dessa superfície.
O que as checkboxes do Rails já fazem
Antes de recorrer a um valor padrão para uma checkbox, note que o Rails geralmente já resolve isso. Uma checkbox HTML desmarcada não envia nada, e um formulário não tem como dizer “isso estava desmarcado”. Por isso,form.check_box renderiza dois inputs: um campo oculto com o valor 0, e a própria checkbox com o valor 1.
Quando a caixa está marcada, ambos são enviados na ordem do documento. O Rails recebe 0 e depois 1, e usa o último. Quando está desmarcada, só o 0 chega. O resultado é que uma checkbox do Rails sempre envia algo, e raramente você precisa de um valor padrão para ela.
Um valor padrão não é autorização
Valores padrão perdem para valores enviados. É isso que os torna valores padrão. Portanto, um valor padrão não pode impedir que um usuário defina um valor: qualquer pessoa que envie a chave o sobrescreve. Para atributos que o usuário não deve controlar, como o autor de um registro, não expresse essa intenção como um valor padrão:user_id não é permitido, então não pode ser atribuído em massa de forma alguma. A propriedade vem da sessão, e não da requisição. Use with_defaults para valores padrão genuínos, nos quais é aceitável que um usuário sobrescreva o valor.
Vendo o que foi enviado
Quando um valor padrão não se comporta como esperado, a questão é quase sempre o que a requisição continha. Localmente, você pode ver isso no painel de rede. Em produção, a AppSignal registra os parâmetros da requisição em traces de erro e performance. Uma issue então mostra os parâmetros que realmente o produziram, e não os que você supôs. Como parâmetros costumam conter dados pessoais, revise o que está sendo enviado. A AppSignal oferece suporte à filtragem de parâmetros para que chaves sensíveis nunca sejam transmitidas. Configure isso antes de confiar nos dados de parâmetros em issues.Transcrição
Transcrito do vídeo e levemente editado. As legendas automáticas entenderam errado vários nomes de produtos e de APIs, e esses foram corrigidos.Ler a transcrição
Ler a transcrição
0:02 Olá pessoal, neste episódio vamos falar sobre os parâmetros do Action Controller, e especificamente sobre o método aqui embaixo, with defaults. Isso é só um alias para reverse merge, mas é uma daquelas coisas que eu costumo ver com frequência e que eu mesmo costumo fazer nos nossos controllers quando preciso atribuir alguns valores padrão. Então vamos dar uma olhada em um exemplo. Vamos gerar um scaffold para um model post, e queremos que o post pertença a um usuário. E também queremos que o post tenha um título e um corpo que seja uma coluna de texto.0:41 Então vamos criar isso. Vamos rodar
rails db:migrate, abrir isso no nosso editor, e o nosso controller de post aqui vai gerar isso. Mas a parte importante aqui é que queremos que esse novo post atribua de fato um valor padrão para essa referência de user. Então podemos dizer current user aqui, e simplesmente atribuir isso. Mas o que seria realmente bom é se pudéssemos fazer isso como parte dos parâmetros que estão chegando, e é exatamente isso que podemos fazer.1:12 Então, em vez de deixar essa linha aqui na nossa action create um pouco mais complicada, podemos usar with defaults aqui, e dizer que user vai ser current user. Bem, eu não tenho um método current user, então vamos apenas usar user.first para isso. E não queremos que o usuário possa escolher quem escreveu o post, então vamos garantir que user ID não esteja nos parâmetros permitidos aqui. Se formos ao nosso formulário de post, podemos remover o user ID, e isso basicamente vai usar esse hash primeiro, e depois fazer merge de quaisquer campos title e body que vieram nos parâmetros. Você também pode usar isso para outras coisas, como talvez uma checkbox ou um array ou algo que pode ou não ser enviado pelo navegador. Você pode especificar seu hash de parâmetros padrão aqui, e eles podem então ser sobrescritos por coisas enviadas pelo navegador.2:11 Então essa é uma funcionalidade pequena e muito interessante. Vamos abrir nosso servidor Rails agora, e ir para slash posts slash new. Podemos colocar test e test. Se criarmos esse post, vamos receber o user ID número um atribuído aqui por causa desse with defaults. Então isso é basicamente só o reverse merge que já vem embutido em um hash, mesmo que os parâmetros do Action Controller não herdem de fato de um hash.2:41 Então, se formos ao GitHub para ver isso, você vai perceber, se olharmos a implementação, que existem todos esses métodos que correspondem a hashes, como merge, values at, compact, blank, compact, enfim. Temos todos esses detalhes de implementação que fazem isso funcionar como um hash na maioria dos casos. Mas se voltarmos para a classe e procurarmos class Parameters, você vai ver que ela não herda de fato de um hash, ela só funciona como um. Então essa é uma coisinha realmente útil que o Colin me ensinou outro dia: basicamente, usando with defaults, podemos ter isso como um hash base de valores. Se quisermos o user aqui, podemos fazer isso.3:29 Poderíamos fazer isso para valores padrão em radio buttons ou checkboxes, ou seja qual for o caso, um array. E essa é simplesmente uma ótima forma de fazer isso caso o navegador não envie de fato alguma coisa. A outra opção é o que as checkboxes fazem no navegador: se você tem um F.checkbox no seu formulário de post, se colocarmos aqui form.checkboxhello, checkboxes não são enviadas ao navegador a menos que estejam realmente marcadas. Então não há como desmarcar isso nos seus formulários. Check underscore box.4:11 Então o que você vai ver aqui é que temos esse input hello, que é um valor oculto e define o valor como zero. Então, se isso não estiver marcado, esse valor oculto será enviado, e eles chegam em uma ordem no formulário. Então, sempre que isso estiver marcado, ele vai enviar o valor zero e depois o valor um, e os parâmetros do Rails conseguem descobrir que sim, o último valor é o que você realmente quer na sua aplicação Rails. Então, se atualizarmos nosso post e formos olhar a requisição de rede, vamos ver que post hello zero foi enviado, mas também post hello one. E se editarmos esse post sem marcar a checkbox, podemos verificar esse payload.5:02 Post hello zero era só zero. Não havia um one para a checkbox marcada porque ela não estava marcada. Então você pode usar inputs dentro do seu HTML para tentar fazer isso funcionar para valores padrão. Mas se houver algum caso em que você quer que o servidor defina isso, por exemplo, queremos garantir que o current user seja definido aqui pelo servidor e não queremos que o usuário envie isso, então podemos usar o método with defaults para cuidar disso, o que eu achei incrivelmente útil e incrivelmente prático. E fiquei surpreso por não ter aprendido isso antes.5:38 Então achei que isso daria um screencast perfeito para compartilhar com vocês. Então é isso para este episódio. Espero que tenham gostado. E a gente se fala no próximo. Peace.Tutoriais relacionados
Sobre este tutorial
Este tutorial resume um screencast do GoRails sobrewith_defaults para parâmetros do Action Controller, de Chris Oliver. O screencast é o trabalho original. O GoRails o publica, junto com o restante da série, em gorails.com.