What is the use of hello_view.ex in Phoenix - phoenix-framework

I was reading the 'Programming Phoenix' book to create my first MVC simple routing project. In the book, it says to create a 'hello_view.ex', and it's under the view section in MVC. But there is already a view in templates. This feels very confusing.
Also, they told me to put hello_world.html inside 'hello' folder in templates. Can I change this folder name? Why can't I rename it? In 'hello_controller.ex', it says 'hello_world.html', not 'hello/hello_world.html'

Phoenix views aren't HTML templates with embedded programming language like html.erb, but the names are similar to the ones in Django, where view means code for displaying data and template means actual HTML with embedded Elixir code (and they have extension eex).
According to the official guide for Phoenix Framework, short info about views:
They also act as a presentation layer for raw data from the controller, preparing it for use in a template. Functions which perform this transformation should go in a view.
Check this out:
Ruby on Rails flow:
router.rb -> Controller (-> Model) -> view in html.erb
Django flow:
urls.py -> View (act like Controller) -> Template
Phoenix flow:
endpoint (in lib) -> router (in web) -> Controller -> View -> Template
The Phoenix flow seems to be longer, but it's not. The biggest advantage for you:
You have explicit control over the middleware!
Remember that- framework does the magic for you, but explicitly. You exactly see what macros and other stuff are called.
Edit
Check out the stuff that's imported when using use in your code.
In your controller you're using Phoenix.Controller stuff, which provides you render function.
You call render with conn, template and assigns parameters. In deps/phoenix/lib/phoenix/controller.ex you have this render
function stored and in the private function do_render line:
view = Map.get(conn.private, :phoenix_view) ||
raise "a view module was not specified, set one with put_view/2"
Gets your View name from the current connection.
And few lines later uses it:
Phoenix.View.render_to_iodata(view, template, Map.put(conn.assigns, :conn, conn))
This call uses internally render in deps/phoenix/lib/phoenix/view.ex
and then render_within, but the name of the folder is set in __using__
use Phoenix.Template, Phoenix.View.__template_options__(__MODULE__, unquote(opts))
which calls __template__options where following lines are placed:
module
|> Module.split()
|> Enum.take(1)
|> Module.concat()
which does the Hello from Hello.PageView or whatever the name is.
Edit2
About changing default view in controller (info from Phoenix documentation):
By default, Controllers render templates in a view with a similar name
to the controller. For example, MyApp.UserController will render
templates inside the MyApp.UserView. This information can be
changed any time by using render/3, render/4 or the put_view/2
function:
def show(conn, _params) do
render(conn, MyApp.SpecialView, :show, message: "Hello")
end
def show(conn, _params) do
conn
|> put_view(MyApp.SpecialView)
|> render(:show, message: "Hello")
end

Related

Using "helper" method in view

I made a helper in my rails project that makes a request in an external api and get a certain value from it.
def show_CoinPrice coin
begin
coinTicker = JSON.parse(HTTParty.get("https://www.mercadobitcoin.net/api/#{coin}/ticker/").body)
"R$ #{coinTicker["ticker"]["last"].to_number.round}"
rescue
"---"
end
end
However I have doubts if this was a good practice to do (this code caused slowness in my view), there is something I can do better, whether with a controller or something ?!
Thanks.
I think u should request to external API using client-side (JS). Cs fetching API with rails helper it's will run while your server is rendering view.

Using SimpleTemplate in Bottle

I'm new in Frameworks like Bottle and working through the Documentation/Tutorial.
Now I got a Problem with the Template-Engine:
I have a file called index.tpl in my folder views. (it's plain html)
When I use the following Code, it works to display my html:
from bottle import Bottle, SimpleTemplate, run, template
app = Bottle()
#app.get('/')
def index():
return template('index')
run(app, debug=True)
Now I want to implement this engine in my project and dont want to use template()
I want to use it as it stands in the documentation, like:
tpl = SimpleTemplate('index')
#app.get('/')
def index():
return tpl.render()
But if I do so, the Browser shows me just a white page with the word
index
written, instead of loading the template.
In the documentation, there is no further information on how I use this OO approach.
I just couldn't figure out why this happens and how I have to do it right...
Here's a nice, simple solution in the spirit of your original question:
tpl = SimpleTemplate(name='views/index.tpl') # note the change here
#app.get('/')
def index():
return tpl.render()

Proper method to access Play! cache in Scala templates?

I'm running a Play! app using Scala templates. However, I can't find an elegant method to access the Cache in an elegant (or valid) way inside of html templates.
I've tried everything like:
<some html>#play.cache.Cache.get(play.session.getId() + "-account")</some html>
But no luck. Thanks for the proper way to do this!
I found the methodology buried in the old 0.9 Scala documentation. For the time being it's not super-easy but it's 3min do-able. It requires adding a parameter to the controller and template like so:
In your controller, pass session as a parameter
object Application extends Controller {
import views.Application._
def index = {
html.index(session)
}
}
At the top of your template, define the implicit variable:
#(implicit session:play.mvc.Scope.Session)
Inside the template html, access it like so:
#(play.cache.Cache.get(session.getId() + "-account"))

render individual file in middleman

I am writing a helper and I need to get a rendered file as String.
I see that the method that I need exists in the middleman's library: http://rubydoc.info/github/middleman/middleman/Middleman/CoreExtensions/Rendering/InstanceMethods#render_individual_file-instance_method
How do I call this function from my helper class?
I tried:
require "middleman-core/lib/middleman-core/core_extensions/rendering.rb"
...
puts Middleman::CoreExtensions::Rendering::InstanceMethods.render_individual_file(filepath)
But it does not seem to find the file, any idea?
I'm not sure 3.0 beta is quite ready for primetime.
That said, it does sound like the partial method is what you're looking for.
Unless I'm missing something, the Middleman method seems like an overly-complex solution. For one of my sites I wanted to load entire text files into my templates, so I wrote this helper:
# Shortcut for loading raw text files. Obviously assumes that given file is in a valid format.
# #return [String] File contents
def load_textfile(filename)
File.read filename.to_s
end
Also, you should clarify if you are intending to use this within a template, or within Ruby code. It's not clear to me based on your question.
Here is an example of how one would use above helper:
Currently of note, Middleman is in the process of transitioning to version 4, and the conventions for loading helpers will change. The most straightforward way to define a helper is within a helper block in your config.rb file, as follows:
helpers do
# Define helper functions here to make them available in templates
end
I use Slim for templating. It really is the best. In slim you would appply helper as thus:
= load_textfile 'path'
p You can embed helper output in your page with interpolation, too: #{load_textfile 'path'}

Ruby - Difference between :variable and #variable

As a Ruby on Rails newbie, I understand that the "#" and ":" references have different meanings. I saw this post in SO, which described some of the differences.
# indicates a instance variable (e.g., #my_selection)
: indicates an alias (e.g., :my_selection)
I ran into a situation where I had a standard MVC page, similar to all of the other forms/pages in my webapp.
html.erb snippet
<%= form_for #my_selection do |f| %>
route.rb snippet
resources :my_selections
When I attempt to access this page, I get this error:
NoMethodError in selections#create
Showing C:/somedir/myapp/app/views/my_selections/index.html.erb where line #16 raised:
undefined method `my_selection_index_path' for #<#<Class:0x1197e5676>:0x25439c3b>
Line 16 is the form snippet shown above.
All of my other forms/pages in the same web app are set up in exactly the same way and are working fine. However, once I changed the erb form reference to :my_selection, this error went away and my page behaved normally.
Questions:
Is my understanding of the difference between :my_selections and #my_selections correct?
Why would switching to :my_selection resolve my original error?
Is my understanding of the difference between :my_selections and
#my_selections correct?
Nope :(
: indicates a symbol, its not an alias for anything intrinsically. It's like an immutable string, which is often used as a name to represent something.
In places where the Rails api accepts a symbol in place of an instance variable, internally it's actually doing this:
self.instance_variable_get "##{my_symbol}"
Which actually returns the value of the requested instance variable.
So the only reason that you think symbol correspond to instance variable at all, is because the code that drives the API you are using works that way. Without a framework to do that for you, there is no correlation at all.
Why would switching to :my_selection resolve my original error?
for_form(model_instance) will generate a form that submits to the create action if the model instance is unsaved, or to the update action if the model is already exiting in your DB.
No I don't know what's in #my_selection, but whatever class it is doesn't seem to be generating the routes properly.
resources :my_selections
Will generate a route you would invoke like this:
my_selections_path
How your form is generating a route for my_selection_index_path I'm not sure and it really depends on what your models are.
And when you pass a symbol instead, and there is no corresponding ivar, it uses that as the model name for route generation. Which would do the right thing by trying to invoke my_selections_path, which is directly based on the symbol you pass in.

Resources