Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic fields in views #272

Closed
whatyouhide opened this issue Aug 31, 2022 · 3 comments · Fixed by #273
Closed

Dynamic fields in views #272

whatyouhide opened this issue Aug 31, 2022 · 3 comments · Fixed by #273

Comments

@whatyouhide
Copy link
Contributor

Currently, if I define some fields in my JSONAPI.View.fields/0 callback that are not part of the data passed when rendering, then I have to define one public function per such field.

This is alright, but it limits flexibility when we need something akin to dynamic fields. For example, imagine that for convenience I keep my data structure as

%{
  id: 1,
  attrs: %{foo: true, bar: false, baz: nil}
}

With the current capabilities, I can do this:

def fields do
  [:id, :foo, :bar, :baz]
end

def foo(%{attrs: %{foo: foo}}, _conn), do: foo
def bar(%{attrs: %{bar: bar}}, _conn), do: bar
def baz(%{attrs: %{baz: baz}}, _conn), do: baz

It works, but imagine what this can become if you want to do something similar with many more fields. Metaprogramming can come in handy if you generate the public functions programmatically, but it leads to code that's a bit harder to understand (especially for newcomers).

Possible Solution

A possible solution could be a c:JSONAPI.View.get_field/3 callback that takes the field name, the data, and the Plug connection. I would reimplement the example above as:

def fields do
  [:id, :foo, :bar, :baz]
end

def get_field(field, %{attrs: attrs}, _conn) do
  Map.fetch!(attrs, field)
end

Did I missing an already-existing way to do this? 🙃 What are you folks' thoughts on it in case I didn't?

@mattpolzin
Copy link
Member

Seems reasonable. I imagine it would be beneficial to still allow individually defined functions named after fields to take precedence over get_field/3.

So for the following

def fields do
  [:id, :foo, :bar, :baz]
end

def foo(attrs, conn), do: ...

def get_field(field, attrs, conn), do: ...

The framework would be expected to call foo/2 for the foo attribute but call get_field/3 for all other attributes.

@whatyouhide
Copy link
Contributor Author

Yes, exactly. I'll work on a PR for this 🙃

@whatyouhide
Copy link
Contributor Author

@mattpolzin PR open #273!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants