Representation doesn't appear to recurse on Properties that are also representable
Using Roar/Representable 2.3, 2.4 and 3.0. Rails apps but would seem unrelated. Representable is serialising Properties when are themselves Representable. For example below an instance of User is assigned to the created_by attribute of a new Blog. There is already a UserRepresenter available but its not used and hence private information can easily leak.
I realise I can add a specific #getter for the relevant attributes but it would seem to make sense that Representable would use a Representer for Properties that have one?
2.2.2 :002 > b = Blog.new name: 'Blog', description: 'New Blog'
=> #<Blog id: nil, created_by: nil, updated_by: nil, owner_id: nil, group_id: nil, permissions: nil, tags: nil, created_at: nil, updated_at: nil, name: "Blog", slug: nil, description: "New Blog", language: nil, tsvector: nil, copyright_notice: nil, copyrighted_on: nil, mail_address: nil, layout_id: nil>
2.2.2 :003 > u = User.last
User Load (1.4ms) SELECT "users"."tableoid"::regclass as "type", "users".* FROM "users" ORDER BY created_at DESC LIMIT $1 [["LIMIT", 1]]
=> #<User id: "b9dc0139-e453-4c65-8c0c-6b46a13c3d6e", created_by: nil, updated_by: nil, owner_id: nil, group_id: nil, permissions: nil, tags: nil, created_at: "2015-12-20 11:20:04", updated_at: "2015-12-20 11:20:04", name: "System Admin", slug: "system-admin", description: nil, language: "simple", tsvector: "'admin':2A 'system':1A", honorific: nil, given_name: nil, family_name: nil, middle_names: nil, known_as: nil, suffix: nil, formal_address: nil, informal_address: nil, salutation: nil, born_on: nil, died_on: nil, gender_id: nil, name_order: nil, locale: nil, status: nil, login_name: "admin", api_key: "5aa7001622ea81ec1d5fb6674b074a71", password_digest: "$2a$10$4mIUUvt9YKHhuF5KM3A4NuvXXSVleau1Gln/qffci1z...", groups: nil, auth: nil>
2.2.2 :004 > b.created_by = u
=> #<User id: "b9dc0139-e453-4c65-8c0c-6b46a13c3d6e", created_by: nil, updated_by: nil, owner_id: nil, group_id: nil, permissions: nil, tags: nil, created_at: "2015-12-20 11:20:04", updated_at: "2015-12-20 11:20:04", name: "System Admin", slug: "system-admin", description: nil, language: "simple", tsvector: "'admin':2A 'system':1A", honorific: nil, given_name: nil, family_name: nil, middle_names: nil, known_as: nil, suffix: nil, formal_address: nil, informal_address: nil, salutation: nil, born_on: nil, died_on: nil, gender_id: nil, name_order: nil, locale: nil, status: nil, login_name: "admin", api_key: "5aa7001622ea81ec1d5fb6674b074a71", password_digest: "$2a$10$4mIUUvt9YKHhuF5KM3A4NuvXXSVleau1Gln/qffci1z...", groups: nil, auth: nil>
2.2.2 :005 > b
=> #<Blog id: nil, created_by: "b9dc0139-e453-4c65-8c0c-6b46a13c3d6e", updated_by: nil, owner_id: nil, group_id: nil, permissions: nil, tags: nil, created_at: nil, updated_at: nil, name: "Blog", slug: nil, description: "New Blog", language: nil, tsvector: nil, copyright_notice: nil, copyrighted_on: nil, mail_address: nil, layout_id: nil>
# Representer will serialise the complete object assigned to created_by when there is a representer available for it:
2.2.2 :006 > b.extend(V1::BlogRepresenter).to_hash
=> {"@type"=>"blog", "tags"=>nil, "permissions"=>nil, "name"=>"Blog", "description"=>"New Blog", "language"=>nil, "copyright_notice"=>nil, "copyrighted_on"=>nil, "created_at"=>nil, "updated_at"=>nil, "created_by"=>#<User id: "b9dc0139-e453-4c65-8c0c-6b46a13c3d6e", created_by: nil, updated_by: nil, owner_id: nil, group_id: nil, permissions: nil, tags: nil, created_at: "2015-12-20 11:20:04", updated_at: "2015-12-20 11:20:04", name: "System Admin", slug: "system-admin", description: nil, language: "simple", tsvector: "'admin':2A 'system':1A", honorific: nil, given_name: nil, family_name: nil, middle_names: nil, known_as: nil, suffix: nil, formal_address: nil, informal_address: nil, salutation: nil, born_on: nil, died_on: nil, gender_id: nil, name_order: nil, locale: nil, status: nil, login_name: "admin", api_key: "5aa7001622ea81ec1d5fb6674b074a71", password_digest: "$2a$10$4mIUUvt9YKHhuF5KM3A4NuvXXSVleau1Gln/qffci1z...", groups: nil, auth: nil>, "updated_by"=>nil, "slug"=>nil, "id"=>nil, "mail_address"=>nil}
2.2.2 :007 >
I don't understand, please show me your BlogRepresenter.
I am guessing your users property is typed but doesn't have a representer assigned, otherwise Representable would never call to_hash on an object.
Ah, ok, no, if you have an object assigned to a scalar property, it will simply call to_s which results in the document you posted.
The rule in all my gems is: they don't guess anything. If you want the created_at to be represented as a user, you have to say
property :created_at, decorator: UserRepresenter
Nick, got it! Thanks, been a loooooong day and that is, I think, the last piece of my puzzle (and all good running on roar master, thanks for the tip)
Time for a beer then!
BTW, for quicker support, join us here: https://gitter.im/trailblazer/chat