3

I have tried to use the suggested example from github. You can also find it on some answers like this one for Rails 4.

I have tried this in Rails 5.0.1 and I just get an empty hash {} stored in the database:

def proposal_params
  params.require(:proposal).permit(:document, :account_id).tap do |whitelisted|
    whitelisted[:document] = params[:proposal][:document]
  end
end

Obviously if I just do permit! it works.

I also tried an answer from this question:

def proposal_params
  params.require(:proposal).permit(:account_id, document: Proposal.stored_attributes[:document])
end

but that also does not work.

The :document attribute contains json which is never the same between requests...and is a long and complex structure.

I just need to dump it as is into a jsonb column.

For the curious, here is an example of what can be in document:

{
   "document":{
      "customer":{
         "id":"273a0ad1-0867-4c17-8e0a-3284c6f2f6af",
         "first_name":"Ricardo",
         "last_name":"Bird",
         "email":"ricardo_bird@smithtrantow.co",
         "mobile":"07786560223"
      },
      "state":8,
      "salutation":"Mr & Mrs Bird",
      "total_price":0,
      "quoted_products":[
         {
            "product":{
               "sku":"9111",
               "name":"Solid European Oak",
               "price":25.99,
               "category":"Wood",
               "sub_category":"Solid",
               "updated_at":"2016-12-01",
               "updated_by":"Donald Duck",
               "created_at":"2016-11-01",
               "created_by":"Mickey",
               "image_url":"http://www.higherground.co.uk/wp-content/uploads/2015/11/wood-flooring-thumbnail.jpg"
            },
            "total_price":25.99,
            "total_area":1,
            "product_total_price":25.99,
            "is_manual_total":false,
            "is_installed":false,
            "install_price":null,
            "are_rooms_grouped":false,
            "rooms":[
               {
                  "name":"Dining Room",
                  "icon_url":"assets/fb-img/dining-room.png",
                  "number":null,
                  "area":1,
                  "width":null,
                  "length":null,
                  "subfloor_prep":null,
                  "subfloor_price":null,
                  "perimeter_product":null,
                  "perimeter_length":null,
                  "is_perimeter_installed":false,
                  "perimeter_price":null,
                  "perimeter_style":null,
                  "is_perimeter_remove_old":false,
                  "is_move_furniture":false,
                  "move_furniture_price":null,
                  "move_surcharge":null,
                  "stairs_stepcount":null,
                  "surcharge":null,
                  "is_installed":false,
                  "uplift_price":null,
                  "install_method":"bonded"
               }
            ],
            "is_extras":true,
            "threshold_count":2,
            "radiator_count":3,
            "trim_count":2,
            "threshold_price":30,
            "radiator_price":4,
            "trim_price":10,
            "is_rear_mat":false,
            "is_front_mat":true,
            "front_mat_type":"Coloured",
            "rear_mat_type":null,
            "front_mat_area":2,
            "front_mat_price":60.01,
            "rear_mat_area":null,
            "rear_mat_price":null,
            "extras_total_price":212.01999999999998
         }
      ],
      "status":"Draft",
      "is_details_oneprice":false,
      "notes":"Testing submission"
   }
}
Community
  • 1
  • 1
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • It seems there is a PR outstanding to provide an easy solution to this here: https://github.com/rails/rails/pull/26308 – rmcsharry Feb 19 '17 at 23:03
  • Could this issue be related to the warning "Unpermitted parameter: document" you get when trying to permit the `document` parameter? –  Feb 19 '17 at 23:10
  • @Pyro Your answer solved it. Thank you! I think the unpermitted parameter message might just be a red herring in this particular case. – rmcsharry Feb 19 '17 at 23:14
  • Great to hear. Oddly your function returns the same result for me, I'm not entirely sure this fixes the cause of the problem. The impending pull request you linked to probably does that. –  Feb 19 '17 at 23:16

2 Answers2

4

If I'm correct you still need to permit! the document parameter:

def proposal_params
  params.require(:proposal).permit(:account_id).tap do |whitelisted|
    whitelisted[:document] = params[:proposal].fetch(:document, ActionController::Parameters.new).permit!
  end
end

The way this works is that it will only keep the account_id at first but then within tap we add the document parameter back by trying to retrieve it from the original parameters. ActionController::Parameters.new as the default value for fetch ensures that the permit! method is always callable even if no document parameter has been passed.

Under the hood ActionController::Parameters#permit! seems to recursively call the permit! function on the contained parameters as well, so we can call it on any instance:

def permit!
  each_pair do |key, value|
    Array.wrap(value).each do |v|
      v.permit! if v.respond_to? :permit!
    end
  end

  @permitted = true
  self
end
  • Thanks for the detailed explanation. This works, thank you. I added a comment to the question to note that there is a solution coming in a future version of Rails to simplify the solution to this problem. – rmcsharry Feb 19 '17 at 23:12
2

You can try:

to_unsafe_hash

See:

http://eileencodes.com/posts/actioncontroller-parameters-now-returns-an-object-instead-of-a-hash/

Graham Slick
  • 6,692
  • 9
  • 51
  • 87