5 ms·
I'm genuinely curious what you feel is too magical with how we handle rendering? Templates are compiled as `render/2` function clauses on the view module, so th
by chrismccord 10y ago
I'm genuinely curious what you feel is too magical with how we handle rendering? Templates are compiled as `render/2` function clauses on the view module, so there's no magic going on. As you said, we do lean on pattern matching, but that's a product of the language and how you structure a large amount of your own code, not anything tricky we're doing.
For example, if I have an `user/index.html.eex` template for a `UserView` module, I can render it with:
View.render(UserView, "index.html", name: "colbyh")
At compile time, we simply precompiled the index.html.eex template as a `def render("index.html", assigns) ...` function clause.
Now imagine I want a `bio.html` template. Instead of making a template file, I can literally do this in my view:
def render("bio.html", assigns) do
"Bio: name: #{name assigns.name}"
end
...
View.render(UserView, "bio.html", name: "colbyh")
=> "Bio: name: colbyh"
And it Just Works exactly because there's no magic going on. Templates are just function calls, whether they are precompiled from a template engine or defined by the user manually.
- bpicolo 10y agoI think the confusion mostly lies in the Views. The difference between controllers and Views and why views are actually necessary to render templates is not especially obvious, and it almost feels like the explicit view layer isn't entirely necessary. (From the developer API perspective, and not necessarily the framework design perspective)
- chrismccord 10y agoThe distinction between views and templates is something that does trip folks up sometimes when coming from other areas that make no distinction or use the terms interchangeably. For us, this distinction is extremely important: - templates are just functions - Views render templates and serve as a presentation layer
- phlakaton 10y agoI'm just starting to learn Elixir and Phoenix. Here are two little bits of "magic" that have thrown me for a loop so far: 1. @var's in templates are not module attributes (though they do seem to be convenient!) 2. The form for `use` is different in Phoenix than it is in Elixir proper – instead of passing opts, you pass an atom that selects the implementation of __using__ you want. (This bit of magic makes no particular sense to me – why wouldn't you just use a submodule, say MyApp.Controller, that has the correct and single __using__ attached?)
- colbyh 10y agoyou can define `__using__` any way you want, and phoenix's default isn't technically any different. it's just a convention that you can choose to use or not, personally I try to rip out a lot of what the `web.ex` file does because I like being more explicit.
- true_religion 10y ago> The form for `use` is different in Phoenix than it is in Elixir proper – instead of passing opts, you pass an atom that selects the implementation of __using__ you want. This isn't really true. If you check out the ExUnit, you can pass something like "use ExUnit.Case, aysnc: true" and it'll setup your module to run tests asynchronously. You can pass any atom/value combination into use. HTTPoision.Base, and ExAws to name a few other projects also have the convention of passing options into __using__. To me, the confusion comes from the fact that the Elixir get-started documentation doesn't say anything about this. It is however listed in the Kernel forms that "use Module" actually just translates to Module.__using__([])
- phlakaton 10y agoThat's the point though - in those cases, you're passing a keyword list, a set of options, instead of an atom which acts as a selector. IIUC the Web module violates the convention attached to and documented for `use`, which to me, who was already wrangling with the subtleties of what `use` does compared to, say, Ruby's include, or Elixir's alias/import, was a bit of confusing (and relatively unconventional) magic.
- colbyh 10y agoit's entirely possible that I learned the framework pretty early on and not keeping up with small API changes has made it seem more complex than it needs to be. I seem to remember earlier documentation using a lot of render calls directly in the controller, and add to that the fact that view functions were available to both controller modules and templates without any explicit inclusions muddied the waters a bit. your explanation makes total sense though and the documentation is now clearer than I remember so chalk it up to growing pains? haha. and having templates that precompile to render functions is pretty magical, tbh. would personally love it if the view documentation reflected this on some level.
- chrismccord 10y agoOur view system has been like this from day one, so not growing pains, but it's possible our documentation wasn't as comprehensive early on. > having templates that precompile to render functions is pretty magical, tbh. would personally love it if the view documentation reflected this on some level. You mean like in our nicely formatted ExDocs? :) The docs walk you through similar examples as I've posted here, but go more in depth. https://hexdocs.pm/phoenix/Phoenix.View.html https://hexdocs.pm/phoenix/Phoenix.View.html
- colbyh 10y agobad choice of words, I meant more of us growing to understand the framework. and since you've had to answer these sorts of questions before I def feel a little less crazy: http://www.jeramysingleton.com/phoenix-templates-are-just-functions/ http://www.jeramysingleton.com/phoenix-templates-are-just-fu... and thanks for keeping up work on the docs!