to_json(only)

9 views
Skip to first unread message

cra...@gmail.com

unread,
Aug 6, 2021, 4:09:43 PMAug 6
to sequel-talk
I'm trying to restrict the number of JSON fields that are returned by a Sinatra app's endpoint.

The model:

class FooBar< Sequel::Model    
    plugin :json_serializer
   ...
end

If I filter the model using a WHERE statement, which returns an array, the fields aren't restricted:

    @results = FooBar

    if params[:a] # => 'foo'
        @results = @results.where( a: params[:a] )
    end

    @results.all.to_json(only: [:a,:b])

    {
        "a": "foo",
        "b": "bar",
        "c": "baz",
        "d": "xxx"
    }

          I've also tried @results.naked.to_json() with the same results.

If I select using the primary key, however, the columns are restricted:

    FooBar['foo'].to_json(only: [:a,:b])

    {
        "a": "foo",
        "b": "bar"
    }

Are arrays of instances supported?

I'm using the tiny_tds gem to connect to MSSQL, if that makes a difference.

Jeremy Evans

unread,
Aug 6, 2021, 4:46:43 PMAug 6
to seque...@googlegroups.com
On Fri, Aug 6, 2021 at 1:09 PM cra...@gmail.com <cra...@gmail.com> wrote:
I'm trying to restrict the number of JSON fields that are returned by a Sinatra app's endpoint.

The model:

class FooBar< Sequel::Model    
    plugin :json_serializer
   ...
end

If I filter the model using a WHERE statement, which returns an array, the fields aren't restricted:

    @results = FooBar

    if params[:a] # => 'foo'
        @results = @results.where( a: params[:a] )
    end

Just FYI, this is a bad idea from a security perspective.  You should make sure the result of params[:a] is the expected type (typecast/raise if not).
 
In general, it's best to handle your requirement by selecting only the columns you need:

  @results = @results.select(:a, :b)

Then you don't need to use options to to_json.


    @results.all.to_json(only: [:a,:b])

This calls Array#to_json, not Sequel::Dataset#to_json.  You should not expect Array#to_json to support the same options as Sequel::Dataset#to_json.

You could switch to:

@results.to_json(only: [:a, :b])

However, the approach using Sequel::Dataset#select ,as shown above, is better, unless you will be needing the columns for some other reason. 
 

    {
        "a": "foo",
        "b": "bar",
        "c": "baz",
        "d": "xxx"
    }

          I've also tried @results.naked.to_json() with the same results.

If I select using the primary key, however, the columns are restricted:

This calls Sequel::Model#to_json, which supports the :only option.
 

    FooBar['foo'].to_json(only: [:a,:b])

    {
        "a": "foo",
        "b": "bar"
    }

Are arrays of instances supported?

They are.  In general, if you are creating the JSON from a dataset, call #to_json on the dataset, instead of calling #all to return an array on instances, and then calling #to_json on that.  However, you can call the class method (Sequel::Model.to_json) with an :array option if you have an existing array of model instances:

FooBar.to_json(array: @results.all, only: [:a, :b])

Thanks,
Jeremy

cra...@gmail.com

unread,
Aug 6, 2021, 4:53:45 PMAug 6
to sequel-talk
Thanks for the help.
Reply all
Reply to author
Forward
0 new messages