Rails 4 - Parâmetros Fortes - Objetos Aninhados

144

Eu tenho uma pergunta bem simples. Mas ainda não encontrei uma solução.

Então, aqui está a string JSON que eu envio ao servidor:

{
  "name" : "abc",
  "groundtruth" : {
    "type" : "Point",
    "coordinates" : [ 2.4, 6 ]
  }
}

Usando o novo método de permissão, eu tenho:

params.require(:measurement).permit(:name, :groundtruth)

Isso não gera erros, mas a entrada do banco de dados criada contém, em nullvez do valor de groundtruth.

Se eu apenas definir:

params.require(:measurement).permit!

Tudo é salvo como esperado, mas é claro que isso mata a segurança fornecida por parâmetros fortes.

Encontrei soluções, como permitir matrizes, mas não um único exemplo usando objetos aninhados. Isso deve ser possível de alguma forma, pois deve ser um caso de uso bastante comum. Então, como isso funciona?

Benjamin M
fonte
Dê uma olhada neste stackoverflow.com/questions/14483963/…
Rajarshi Das
1
@vinodadhikary Estava correto… acho que o OP está confuso. Por mais estranho que pareça quando você deseja permitir atributos aninhados, você especifica os atributos do objeto aninhado na matriz. Por outro lado, se você deseja aninhar vários objetos, envolva-o em um hash ... consulte api.rubyonrails.org/classes/ActionController/… e github.com/rails/rails/blob/master/actionpack/lib/…
j03w 26/08/13
@ j03w, Obrigado pelo link para a fonte. Está claro agora. Você deve adicionar uma resposta aqui para esse achado, pois acho que ajudará muitas outras pessoas.
vee

Respostas:

181

Por mais estranho que pareça quando você deseja permitir atributos aninhados, você especifica os atributos do objeto aninhado em uma matriz. No seu caso, seria

Atualizar como sugerido por @RafaelOliveira

params.require(:measurement)
      .permit(:name, :groundtruth => [:type, :coordinates => []])

Por outro lado, se você deseja aninhar vários objetos, envolva-o em um hash ... assim

params.require(:foo).permit(:bar, {:baz => [:x, :y]})


Os Rails realmente têm uma documentação muito boa sobre isso: http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit

Para esclarecimentos adicionais, você pode examinar a implementação permite strong_parametersela própria: https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb#L246-L247

j03w
fonte
5
os dois casos são os mesmos nesta resposta; na verdade, apenas os colchetes são opcionais em torno de {: groundtruth => [...]}; É um hash, mas o intérprete é capaz de determinar onde o hash começa e termina sem colchetes explícitos.
speakingcode
Matrizes aninhadas de atributos não permitem atributos aninhados. Atributos aninhados e attr_accessor estão listados no meu aplicativo como "Parâmetros não permitidos". Ainda à procura de uma solução segura.
Katarzyna
No caso de vários objetos aninhados, você também deve permitir que o ID funcione. Mais informações aqui: stackoverflow.com/questions/18308714/…
Fabrice Carrega
1
Isso permite apenas UM conjunto de atributos aninhados. Isso não funcionará no caso de um para muitos.
AKWF 10/0318
23

Achei esta sugestão útil no meu caso:

  def product_params
    params.require(:product).permit(:name).tap do |whitelisted|
      whitelisted[:data] = params[:product][:data]
    end
  end

Verifique este link do comentário de Xavier no github.

Essa abordagem coloca na lista de permissões todo o objeto de parâmetros [: measure] [: groundtruth].

Usando os atributos de perguntas originais:

  def product_params
    params.require(:measurement).permit(:name, :groundtruth).tap do |whitelisted|
      whitelisted[:groundtruth] = params[:measurement][:groundtruth]
    end
  end
M.ElSaka
fonte
4
Apenas uma observação: Isso ainda será exibido no log como parâmetros não permitidos, mas o modelo os aceitará de qualquer maneira.
Weston Ganger
5
Não tenho certeza do Rails 4, mas no meu projeto do Rails 5 eu tenho que ligar permit!para estar na lista de permissões, caso contrário ele permanecerá não permitido depois de tocar nele. Neste caso, seriaparams[:measurement][:groundtruth].permit!
nayiaw
@nayiaw eu também recebo a mensagem não permitida, mas adicionar permit!aumenta essa NoMethodError (undefined method permissão de erro ! ' for # <Array: 0x007f80cb71ea00>): `
wuliwong
O permit!método @wuliwong não está disponível em Array. Você precisará ter acesso à respectiva instância de classe para ter acesso permit!(já faz algum tempo, esqueci o nome da classe, mas é algo ActionController::Parametersbaseado nesta página ).
Nayiaw 18/04
8

Permitindo um objeto aninhado:

params.permit( {:school => [:id , :name]}, 
               {:student => [:id, 
                            :name, 
                            :address, 
                            :city]},
                {:records => [:marks, :subject]})
Codiee
fonte
0

Se for o Rails 5, por causa da nova notação de hash: params.permit(:name, groundtruth: [:type, coordinates:[]])funcionará bem.

user8164115
fonte