Rails uses a multi-step process to render templates:
1. It creates an ActionView::Base rendering context instance to provide an isolated environment for the template.
2. It collects information needed for finding the template, like the locale, format, and view paths.
3. It searches the view paths by iterating through the resolvers and using a "query" built from the template name, prefixes, and other details to find a matching template file.
model.search: customize your own search logicTse-Ching Ho
This is a lightning talk in Rubyconf Taiwan 2010. I talk about the principles of how to customize your own Model.search method for rails 3. Meta search is an implementation for this purpose and also an available replacement of searchlogic for now.
JavaScript is the language of Web. It has its own styles and vocabulary, which is very different from languages we are familiar with like C, C++, Java, C# etc. While not having classes and functions to be acting as FIRST CLASS CITIZENS for most of the tasks sometimes its difficult to manage very large JavaScript files. And, there comes the need of a common pattern for writing efficient JavaScript.
For a presentation given to the Angular DC Meetup on 3/19/14. (http://www.meetup.com/AngularJS-DC/events/169813802/) Part 2 of the "Angular from Scratch" series. Find part one at http://christianlilley.wordpress.com/2013/11/15/angular-from-scratch-slides-from-angularjs-meetup-dc/ . Find the accompanying demonstration files at https://github.com/xmlilley/ng-demos.
How to effectively utilize roles and capabilities in WordPress eludes many developers. Working with them can seem tricky and rigid, but it doesn’t have to be.
This presentation will have a brief overview of roles and capabilities in WordPress and how a developer can create their own. We will then move into a discussion of the user_has_cap and map_meta_cap filters, which enable developers to precisely manipulate capabilities without having to write anything to the database.
Caching is one of the most popular ways to optimize the performance of web applications. Magento is not far from this trend and the primary approach to speed up slow code from the core team is to cache it. This approach works well for small projects where the rate of inventory changes is shallow. But as soon as you enter sales season or receive regular product updates from the external system, your cache hit ratio plummets. In this talk, you will learn how to ensure that your system’s uncached response times are as light as possible when you get a cache miss by minimizing the I/O of your application with intelligent batch data preloading.
model.search: customize your own search logicTse-Ching Ho
This is a lightning talk in Rubyconf Taiwan 2010. I talk about the principles of how to customize your own Model.search method for rails 3. Meta search is an implementation for this purpose and also an available replacement of searchlogic for now.
JavaScript is the language of Web. It has its own styles and vocabulary, which is very different from languages we are familiar with like C, C++, Java, C# etc. While not having classes and functions to be acting as FIRST CLASS CITIZENS for most of the tasks sometimes its difficult to manage very large JavaScript files. And, there comes the need of a common pattern for writing efficient JavaScript.
For a presentation given to the Angular DC Meetup on 3/19/14. (http://www.meetup.com/AngularJS-DC/events/169813802/) Part 2 of the "Angular from Scratch" series. Find part one at http://christianlilley.wordpress.com/2013/11/15/angular-from-scratch-slides-from-angularjs-meetup-dc/ . Find the accompanying demonstration files at https://github.com/xmlilley/ng-demos.
How to effectively utilize roles and capabilities in WordPress eludes many developers. Working with them can seem tricky and rigid, but it doesn’t have to be.
This presentation will have a brief overview of roles and capabilities in WordPress and how a developer can create their own. We will then move into a discussion of the user_has_cap and map_meta_cap filters, which enable developers to precisely manipulate capabilities without having to write anything to the database.
Caching is one of the most popular ways to optimize the performance of web applications. Magento is not far from this trend and the primary approach to speed up slow code from the core team is to cache it. This approach works well for small projects where the rate of inventory changes is shallow. But as soon as you enter sales season or receive regular product updates from the external system, your cache hit ratio plummets. In this talk, you will learn how to ensure that your system’s uncached response times are as light as possible when you get a cache miss by minimizing the I/O of your application with intelligent batch data preloading.
Writing HTML5 Web Apps using Backbone.js and GAERon Reiter
A walkthrough of how to write a complete HTML5 web app (both front end and back end) using Google App Engine (Python), Backbone.js, Require.js, underscore.js and jQuery.
This presentation has been developed in the context of the Mobile Applications Development course, DISIM, University of L'Aquila (Italy), Spring 2016.
http://www.ivanomalavolta.com
In this talk I introduced the language Goby, which I created half years ago. I also explained how expressions in Ruby/Goby could cause stack overflow and how to avoid them.
Software Engineering, Software Consulting, Tech Lead, Spring Boot, Spring Cloud, Spring Core, Spring JDBC, Spring Transaction, Spring MVC, OpenShift Cloud Platform, Kafka, REST, SOAP, LLD & HLD.
May Marketo Masterclass, London MUG May 22 2024.pdfAdele Miller
Can't make Adobe Summit in Vegas? No sweat because the EMEA Marketo Engage Champions are coming to London to share their Summit sessions, insights and more!
This is a MUG with a twist you don't want to miss.
Essentials of Automations: The Art of Triggers and Actions in FMESafe Software
In this second installment of our Essentials of Automations webinar series, we’ll explore the landscape of triggers and actions, guiding you through the nuances of authoring and adapting workspaces for seamless automations. Gain an understanding of the full spectrum of triggers and actions available in FME, empowering you to enhance your workspaces for efficient automation.
We’ll kick things off by showcasing the most commonly used event-based triggers, introducing you to various automation workflows like manual triggers, schedules, directory watchers, and more. Plus, see how these elements play out in real scenarios.
Whether you’re tweaking your current setup or building from the ground up, this session will arm you with the tools and insights needed to transform your FME usage into a powerhouse of productivity. Join us to discover effective strategies that simplify complex processes, enhancing your productivity and transforming your data management practices with FME. Let’s turn complexity into clarity and make your workspaces work wonders!
E-commerce Application Development Company.pdfHornet Dynamics
Your business can reach new heights with our assistance as we design solutions that are specifically appropriate for your goals and vision. Our eCommerce application solutions can digitally coordinate all retail operations processes to meet the demands of the marketplace while maintaining business continuity.
Zoom is a comprehensive platform designed to connect individuals and teams efficiently. With its user-friendly interface and powerful features, Zoom has become a go-to solution for virtual communication and collaboration. It offers a range of tools, including virtual meetings, team chat, VoIP phone systems, online whiteboards, and AI companions, to streamline workflows and enhance productivity.
Navigating the Metaverse: A Journey into Virtual Evolution"Donna Lenk
Join us for an exploration of the Metaverse's evolution, where innovation meets imagination. Discover new dimensions of virtual events, engage with thought-provoking discussions, and witness the transformative power of digital realms."
GraphSummit Paris - The art of the possible with Graph TechnologyNeo4j
Sudhir Hasbe, Chief Product Officer, Neo4j
Join us as we explore breakthrough innovations enabled by interconnected data and AI. Discover firsthand how organizations use relationships in data to uncover contextual insights and solve our most pressing challenges – from optimizing supply chains, detecting fraud, and improving customer experiences to accelerating drug discoveries.
Mobile App Development Company In Noida | Drona InfotechDrona Infotech
Looking for a reliable mobile app development company in Noida? Look no further than Drona Infotech. We specialize in creating customized apps for your business needs.
Visit Us For : https://www.dronainfotech.com/mobile-application-development/
Quarkus Hidden and Forbidden ExtensionsMax Andersen
Quarkus has a vast extension ecosystem and is known for its subsonic and subatomic feature set. Some of these features are not as well known, and some extensions are less talked about, but that does not make them less interesting - quite the opposite.
Come join this talk to see some tips and tricks for using Quarkus and some of the lesser known features, extensions and development techniques.
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxrickgrimesss22
Discover the essential features to incorporate in your Winzo clone app to boost business growth, enhance user engagement, and drive revenue. Learn how to create a compelling gaming experience that stands out in the competitive market.
Do you want Software for your Business? Visit Deuglo
Deuglo has top Software Developers in India. They are experts in software development and help design and create custom Software solutions.
Deuglo follows seven steps methods for delivering their services to their customers. They called it the Software development life cycle process (SDLC).
Requirement — Collecting the Requirements is the first Phase in the SSLC process.
Feasibility Study — after completing the requirement process they move to the design phase.
Design — in this phase, they start designing the software.
Coding — when designing is completed, the developers start coding for the software.
Testing — in this phase when the coding of the software is done the testing team will start testing.
Installation — after completion of testing, the application opens to the live server and launches!
Maintenance — after completing the software development, customers start using the software.
AI Genie Review: World’s First Open AI WordPress Website CreatorGoogle
AI Genie Review: World’s First Open AI WordPress Website Creator
👉👉 Click Here To Get More Info 👇👇
https://sumonreview.com/ai-genie-review
AI Genie Review: Key Features
✅Creates Limitless Real-Time Unique Content, auto-publishing Posts, Pages & Images directly from Chat GPT & Open AI on WordPress in any Niche
✅First & Only Google Bard Approved Software That Publishes 100% Original, SEO Friendly Content using Open AI
✅Publish Automated Posts and Pages using AI Genie directly on Your website
✅50 DFY Websites Included Without Adding Any Images, Content Or Doing Anything Yourself
✅Integrated Chat GPT Bot gives Instant Answers on Your Website to Visitors
✅Just Enter the title, and your Content for Pages and Posts will be ready on your website
✅Automatically insert visually appealing images into posts based on keywords and titles.
✅Choose the temperature of the content and control its randomness.
✅Control the length of the content to be generated.
✅Never Worry About Paying Huge Money Monthly To Top Content Creation Platforms
✅100% Easy-to-Use, Newbie-Friendly Technology
✅30-Days Money-Back Guarantee
See My Other Reviews Article:
(1) TubeTrivia AI Review: https://sumonreview.com/tubetrivia-ai-review
(2) SocioWave Review: https://sumonreview.com/sociowave-review
(3) AI Partner & Profit Review: https://sumonreview.com/ai-partner-profit-review
(4) AI Ebook Suite Review: https://sumonreview.com/ai-ebook-suite-review
#AIGenieApp #AIGenieBonus #AIGenieBonuses #AIGenieDemo #AIGenieDownload #AIGenieLegit #AIGenieLiveDemo #AIGenieOTO #AIGeniePreview #AIGenieReview #AIGenieReviewandBonus #AIGenieScamorLegit #AIGenieSoftware #AIGenieUpgrades #AIGenieUpsells #HowDoesAlGenie #HowtoBuyAIGenie #HowtoMakeMoneywithAIGenie #MakeMoneyOnline #MakeMoneywithAIGenie
Launch Your Streaming Platforms in MinutesRoshan Dwivedi
The claim of launching a streaming platform in minutes might be a bit of an exaggeration, but there are services that can significantly streamline the process. Here's a breakdown:
Pros of Speedy Streaming Platform Launch Services:
No coding required: These services often use drag-and-drop interfaces or pre-built templates, eliminating the need for programming knowledge.
Faster setup: Compared to building from scratch, these platforms can get you up and running much quicker.
All-in-one solutions: Many services offer features like content management systems (CMS), video players, and monetization tools, reducing the need for multiple integrations.
Things to Consider:
Limited customization: These platforms may offer less flexibility in design and functionality compared to custom-built solutions.
Scalability: As your audience grows, you might need to upgrade to a more robust platform or encounter limitations with the "quick launch" option.
Features: Carefully evaluate which features are included and if they meet your specific needs (e.g., live streaming, subscription options).
Examples of Services for Launching Streaming Platforms:
Muvi [muvi com]
Uscreen [usencreen tv]
Alternatives to Consider:
Existing Streaming platforms: Platforms like YouTube or Twitch might be suitable for basic streaming needs, though monetization options might be limited.
Custom Development: While more time-consuming, custom development offers the most control and flexibility for your platform.
Overall, launching a streaming platform in minutes might not be entirely realistic, but these services can significantly speed up the process compared to building from scratch. Carefully consider your needs and budget when choosing the best option for you.
Artificia Intellicence and XPath Extension FunctionsOctavian Nadolu
The purpose of this presentation is to provide an overview of how you can use AI from XSLT, XQuery, Schematron, or XML Refactoring operations, the potential benefits of using AI, and some of the challenges we face.
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteGoogle
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
👉👉 Click Here To Get More Info 👇👇
https://sumonreview.com/ai-pilot-review/
AI Pilot Review: Key Features
✅Deploy AI expert bots in Any Niche With Just A Click
✅With one keyword, generate complete funnels, websites, landing pages, and more.
✅More than 85 AI features are included in the AI pilot.
✅No setup or configuration; use your voice (like Siri) to do whatever you want.
✅You Can Use AI Pilot To Create your version of AI Pilot And Charge People For It…
✅ZERO Manual Work With AI Pilot. Never write, Design, Or Code Again.
✅ZERO Limits On Features Or Usages
✅Use Our AI-powered Traffic To Get Hundreds Of Customers
✅No Complicated Setup: Get Up And Running In 2 Minutes
✅99.99% Up-Time Guaranteed
✅30 Days Money-Back Guarantee
✅ZERO Upfront Cost
See My Other Reviews Article:
(1) TubeTrivia AI Review: https://sumonreview.com/tubetrivia-ai-review
(2) SocioWave Review: https://sumonreview.com/sociowave-review
(3) AI Partner & Profit Review: https://sumonreview.com/ai-partner-profit-review
(4) AI Ebook Suite Review: https://sumonreview.com/ai-ebook-suite-review
Graspan: A Big Data System for Big Code AnalysisAftab Hussain
We built a disk-based parallel graph system, Graspan, that uses a novel edge-pair centric computation model to compute dynamic transitive closures on very large program graphs.
We implement context-sensitive pointer/alias and dataflow analyses on Graspan. An evaluation of these analyses on large codebases such as Linux shows that their Graspan implementations scale to millions of lines of code and are much simpler than their original implementations.
These analyses were used to augment the existing checkers; these augmented checkers found 132 new NULL pointer bugs and 1308 unnecessary NULL tests in Linux 4.4.0-rc5, PostgreSQL 8.3.9, and Apache httpd 2.2.18.
- Accepted in ASPLOS ‘17, Xi’an, China.
- Featured in the tutorial, Systemized Program Analyses: A Big Data Perspective on Static Analysis Scalability, ASPLOS ‘17.
- Invited for presentation at SoCal PLS ‘16.
- Invited for poster presentation at PLDI SRC ‘16.
Code reviews are vital for ensuring good code quality. They serve as one of our last lines of defense against bugs and subpar code reaching production.
Yet, they often turn into annoying tasks riddled with frustration, hostility, unclear feedback and lack of standards. How can we improve this crucial process?
In this session we will cover:
- The Art of Effective Code Reviews
- Streamlining the Review Process
- Elevating Reviews with Automated Tools
By the end of this presentation, you'll have the knowledge on how to organize and improve your code review proces
2. About me
Stan Lo
GitHub: @st0012
Twitter: @_st0012
Email: stan001212@gmail.com
Work at Polydice(iCook)
Love to contribute open source projects, currently working on Goby
language
3. Steps for Rails to render template
1. Create the rendering context
2. Prepare for rendering
3. Find template and convert it into an object (most complicated
part)
4. Compile template object into a method
5. Call compiled method and get final result
4. 1. Rails creates an ActionView::Base instance as template
rendering's context.
2. Then collects and initializes the informations Rails needs for
finding a template.
3. Find the template file and use it to create an
ActionView::Template instance.
4. Compile the template object's content into ActionView::Base's
method
5. Call the compiled method on ActionView::Base's instance and
it'll return the final result.
6. Normally we render template in two ways
• Automatically rendering by controller action
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
• Or call render manually
class PostsController < ApplicationController
def search
@posts = Post.search(params[:q])
render :index
end
end
7. Either way, they will both call
ActionView::Rendering#render_to_body
actionview/lib/action_view/rendering.rb
def render_to_body(options = {})
_process_options(options)
_render_template(options)
end
Then call #_render_template
def _render_template(options)
variant = options.delete(:variant)
assigns = options.delete(:assigns)
context = view_context
context.assign assigns if assigns
lookup_context.rendered_format = nil if options[:formats]
lookup_context.variants = variant if variant
view_renderer.render(context, options)
end
8. And I'll use this action as example to explain the rendering process
class PostsController < ActionController::Base
def index
@posts = Post.all
end
end
9. Here's the first phase of template rendering:
Create rendering context
10. Let's take a look a #_render_template
def _render_template(options)
variant = options.delete(:variant)
assigns = options.delete(:assigns)
context = view_context
context.assign assigns if assigns
lookup_context.rendered_format = nil if options[:formats]
lookup_context.variants = variant if variant
view_renderer.render(context, options)
end
11. And we can see the keyword: view_context
def _render_template(options)
variant = options.delete(:variant)
assigns = options.delete(:assigns)
context = view_context
context.assign assigns if assigns
lookup_context.rendered_format = nil if options[:formats]
lookup_context.variants = variant if variant
view_renderer.render(context, options)
end
12. view_context is an instance of view_context_class.
def view_context
view_context_class.new(view_renderer, view_assigns, self)
end
def view_context_class
@_view_context_class ||= self.class.view_context_class
end
Rails initializes it with view_renderer and view_assigns, which represents ActionView::Renderer and instance
variables created in controller. (In our case it's @posts)
13. And this is where the view_context_class comes from.
module ClassMethods
def view_context_class
@view_context_class ||= begin
supports_path = supports_path?
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers(supports_path)
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
14. It turns out Rails creates an anonymous class (which inherites
from ActionView::Base) as view_context_class.
module ClassMethods
def view_context_class
@view_context_class ||= begin
supports_path = supports_path?
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers(supports_path)
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
15. The code here creates an anonymous class that inherits
ActionView::Base
module ClassMethods
def view_context_class
@view_context_class ||= begin
supports_path = supports_path?
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers(supports_path)
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
16. And it will also includes some helpers depends on the context
module ClassMethods
def view_context_class
@view_context_class ||= begin
supports_path = supports_path?
routes = respond_to?(:_routes) && _routes
helpers = respond_to?(:_helpers) && _helpers
Class.new(ActionView::Base) do
if routes
include routes.url_helpers(supports_path)
include routes.mounted_helpers
end
if helpers
include helpers
end
end
end
end
end
17. So view_context can be considered as an instance of
ActionView::Base, which will be created in every rendering.
And its main function is to provide isolated environment for every
template rendering.
19. Let's back to #_render_template. After creates the context, Rails
will call view_renderer's #render method.
def _render_template(options)
......
context = view_context
......
view_renderer.render(context, options)
end
And the view_renderer is actually an ActionView::Renderer's
instance.
22. It stores an instance variable called @lookup_context, which
carries some important info for finding our template. Such as
locale, format, handlers...etc.
class Renderer
attr_accessor :lookup_context
def initialize(lookup_context)
@lookup_context = lookup_context
end
end
23. This is the lookup context created in our example. We'll see it
again later.
#<ActionView::LookupContext:0x007f8763cee608
@cache=true,
@details=
{:locale=>[:en],
:formats=>[:html],
:variants=>[],
:handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]},
@details_key=nil,
@prefixes=["posts", "application"],
@rendered_format=nil,
@view_paths=
#<ActionView::PathSet:0x007f8763cee428
@paths=
[#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=1 queries=0>,
@path="/Users/stanlow/projects/sample/app/views",
@pattern=
":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">]>>
24. Renderer also determines whether we are rendering a partial or a
template, and passes the informations to coorresponding renderer.
def render(context, options)
if options.key?(:partial)
render_partial(context, options)
else
render_template(context, options)
end
end
25. It uses the lookup context it holds to initialize corresponding
renderer.
module ActionView
class Renderer
# Direct access to template rendering.
def render_template(context, options) #:nodoc:
TemplateRenderer.new(@lookup_context).render(context, options)
end
# Direct access to partial rendering.
def render_partial(context, options, &block) #:nodoc:
PartialRenderer.new(@lookup_context).render(context, options, block)
end
end
end
26. I will explain the rest of processes using
TemplateRenderer#render as an example.
27. This is how TemplateRenderer#render looks like:
module ActionView
class TemplateRnderer
def render(context, options)
@view = context
@details = extract_details(options)
template = determine_template(options)
prepend_formats(template.formats)
@lookup_context.rendered_format ||= (template.formats.first || formats.first)
render_template(template, options[:layout], options[:locals])
end
end
end
28. As you can see, our next step is to find the template
module ActionView
class TemplateRnderer
def render(context, options)
@view = context
@details = extract_details(options)
template = determine_template(options)
prepend_formats(template.formats)
@lookup_context.rendered_format ||= (template.formats.first || formats.first)
render_template(template, options[:layout], options[:locals])
end
end
end
29. So here's the third phase: Finding Template
This is the most complicated part in the rendering process, so we'll spend a lot of time here.
30. After calling #determine_template, we then calls #find_template
module ActionView
class TemplateRenderer
def render(context, options)
......
template = determine_template(options)
......
end
def determine_template(options)
......
if ......
elsif options.key?(:template)
# Means Rails already found that template
if options[:template].respond_to?(:render)
options[:template]
else
find_template(options[:template], options[:prefixes], false, keys, @details)
end
........
end
end
end
end
31. But #find_template is actually delegated to @lookup_context
delegate :find_template, :find_file, :template_exists?,
:any_templates?, :with_fallbacks, :with_layout_format,
:formats, to: :@lookup_context
32. So let's take a look at @lookup_context again
#<ActionView::LookupContext:0x007f8763cee608
@cache=true,
@details=
{:locale=>[:en],
:formats=>[:html],
:variants=>[],
:handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]},
@details_key=nil,
@prefixes=["posts", "application"],
@rendered_format=nil,
@view_paths=
#<ActionView::PathSet:0x007f8763cee428
@paths=
[#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=1 queries=0>,
@path="/Users/stanlow/projects/sample/app/views",
@pattern=
":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">]>>
33. It's an instance of ActionView::LookupContext.
And as I said before, it carries some important info for finding
templates like:
• Details
• Prefixes
• View Paths
34. Details: Contains several informations for building a template
searching query later
#<ActionView::LookupContext:0x007f8763cee608
@cache=true,
@details=
{:locale=>[:en],
:formats=>[:html],
:variants=>[],
:handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]},
@details_key=nil,
@prefixes=["posts", "application"],
@rendered_format=nil,
@view_paths=
#<ActionView::PathSet:0x007f8763cee428
@paths=
[#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=1 queries=0>,
@path="/Users/stanlow/projects/sample/app/views",
@pattern=
":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">]>>
36. View Paths: It tells Rails where to look for the template files. For
example: our app's app/views
#<ActionView::LookupContext:0x007f8763cee608
@cache=true,
@details=
{:locale=>[:en],
:formats=>[:html],
:variants=>[],
:handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]},
@details_key=nil,
@prefixes=["posts", "application"],
@rendered_format=nil,
@view_paths=
#<ActionView::PathSet:0x007f8763cee428
@paths=
[#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=1 queries=0>,
@path="/Users/stanlow/projects/sample/app/views",
@pattern=
":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">]>>
37. After received #find_template from template renderer,
LookupContext will call #find on its @view_paths.
module ActionView
class LookupContext
module ViewPaths
def find(name, prefixes = [], partial = false, keys = [], options = {})
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
end
alias :find_template :find
end
include ViewPaths
end
end
38. The @view_paths is an instance of ActionView::PathSet and
contains several resolver instances.
<ActionView::PathSet:0x007f87678f9648
@paths=
[#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=
#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=2 queries=0>,
@path=
"/Users/stanlow/projects/sample/app/views",
@pattern=
":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">]>
39. Every resolver represents a place Rails should looking for
templates, such as app/views in your app or devise's app/views.
<ActionView::PathSet:0x007f87678f9648
@paths=
[
#<ActionView::OptimizedFileSystemResolver:0x007f8763a2f548
@cache=#<ActionView::Resolver::Cache:0x7f8763a2f228 keys=2 queries=0>,
@path="/Users/stanlow/projects/sample/app/views",
@pattern=":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}">
]>
41. After we call #find on PathSet, it will iterate through every
resolvers it has to look for templates.
module ActionView
class PathSet
def _find_all(path, prefixes, args, outside_app)
prefixes.each do |prefix|
paths.each do |resolver|
if outside_app
templates = resolver.find_all_anywhere(path, prefix, *args)
else
templates = resolver.find_all(path, prefix, *args)
end
return templates unless templates.empty?
end
end
[]
end
end
end
42. And every resolver uses #find_templates to search the template
we want from templates it holds.
module ActionView
class Resolver
def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
cached(key, [name, prefix, partial], details, locals) do
find_templates(name, prefix, partial, details)
end
end
def find_all_anywhere(name, prefix, partial=false, details={}, key=nil, locals=[])
cached(key, [name, prefix, partial], details, locals) do
find_templates(name, prefix, partial, details, true)
end
end
end
end
43. Here's the last step for finding a template, I'll split it into several
phases.
44. First, Rails will create a resolver path object.
def find_templates(name, prefix, partial, details, outside_app_allowed = false)
path = Path.build(name, prefix, partial)
......
end
Which looks like:
#<ActionView::Resolver::Path:0x007ffa3a5523a0
@name="index",
@partial=false,
@prefix="posts",
@virtual="posts/index">
45. Then we can use this path object and lookup context's details to
build a query
def find_templates(name, prefix, partial, details, outside_app_allowed = false)
path = Path.build(name, prefix, partial)
query(path, details, details[:formats], outside_app_allowed)
end
def query(path, details, formats, outside_app_allowed)
query = build_query(path, details)
......
end
46. This query is a kind of formal language, you can consider it a
regular expression for matching file's path and extension.
"/Users/stanlow/projects/sample/app/views/posts/index{.en,}{.html,}
{}{.raw,.erb,.html,.builder,.ruby,.coffee,.jbuilder,}"
47. And every resolver will use this query to find the target in its
templates.
def query(path, details, formats, outside_app_allowed)
query = build_query(path, details)
template_paths = find_template_paths(query)
......
template_paths.map do |template|
handler, format, variant = extract_handler_and_format_and_variant(template, formats)
contents = File.binread(template)
Template.new(contents, File.expand_path(template), handler,
virtual_path: path.virtual,
format: format,
variant: variant,
updated_at: mtime(template)
)
end
end
48. If it found a matched template, it returns its absolute path.
["/path_to_your_app/app/views/layouts/application.html.erb"]
49. Finally, Rails can use the absolute path it got to read the file and
use its content to initialize an ActionView::Template's instance.
def query(path, details, formats, outside_app_allowed)
query = build_query(path, details)
template_paths = find_template_paths(query)
......
template_paths.map do |template|
handler, format, variant = extract_handler_and_format_and_variant(template, formats)
contents = File.binread(template)
Template.new(contents, File.expand_path(template), handler,
virtual_path: path.virtual,
format: format,
variant: variant,
updated_at: mtime(template)
)
end
end
50. The above is the third phase of template rendering in Rails.
52. After ActionView::TemplateRenderer found the template, it'll call
#render_template and pass the template object as a argument.
module ActionView
class TemplateRenderer < AbstractRenderer #:nodoc:
def render(context, options)
......
# Found your template
template = determine_template(options)
......
render_template(template, options[:layout], options[:locals])
end
end
end
53. Then Rails will call #render on the template object with locals
(local variables) and the view context.
def render_template(template, layout_name = nil, locals = nil) #:nodoc:
view, locals = @view, locals || {}
render_with_layout(layout_name, locals) do |layout|
instrument(:template, .....) do
# the block will only be execute if your template contains `yield`
template.render(view, locals) { |*name| view._layout_for(*name) }
end
end
end
54. And #render will compile the template into a method and call it
immediately.
def render(view, locals, buffer = nil, &block)
instrument_render_template do
compile!(view)
view.send(method_name, locals, buffer, &block)
end
rescue => e
handle_render_error(view, e)
end
55. Every template will only be compiled once, Rails will check if it has
been compiled before compiles it.
def compile!(view)
return if @compiled
@compile_mutex.synchronize do
return if @compiled
.....
instrument("!compile_template") do
compile(mod)
end
......
@compiled = true
end
end
56. And this is how Template#compile looks like.
def compile(mod)
encode!
method_name = self.method_name
code = @handler.call(self)
source = <<-end_src
def #{method_name}(local_assigns, output_buffer)
_old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};
_old_output_buffer = @output_buffer;#{locals_code};#{code}
ensure
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
end
end_src
......
mod.module_eval(source, identifier, 0)
......
end
57. The source part is a string template that will become a method
definition in Ruby.
source = <<-end_src
def #{method_name}(local_assigns, output_buffer)
_old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};
_old_output_buffer = @output_buffer;#{locals_code};#{code}
ensure
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
end
end_src
58. I'll explain this process with the example partial file: app/views/
users/_hello.html.erb:
Hello <%= user.name %>!
And we render it using
render partial: "users/hello", locals: { user: @user }
59. The source generated with our example would look like this:
"def _app_views_users__hello_html_erb___4079420934646067298_70142066674000(local_assigns, output_buffer)n
_old_virtual_path, @virtual_path = @virtual_path, "users/hello";
_old_output_buffer = @output_buffer
# locals_code
user = user = local_assigns[:user]
# code
@output_buffer = output_buffer || ActionView::OutputBuffer.new;
@output_buffer.safe_append='Hello '.freeze;
@output_buffer.append=( user.name );
@output_buffer.safe_append='!n'.freeze;
@output_buffer.to_sn
ensuren
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffern
endn"
60. First, we need to take a look at locals_code
"def _app_views_users__hello_html_erb___4079420934646067298_70142066674000(local_assigns, output_buffer)n
_old_virtual_path, @virtual_path = @virtual_path, "users/hello";
_old_output_buffer = @output_buffer
# locals_code
user = user = local_assigns[:user]
# code
@output_buffer = output_buffer || ActionView::OutputBuffer.new;
@output_buffer.safe_append='Hello '.freeze;
@output_buffer.append=( user.name );
@output_buffer.safe_append='!n'.freeze;
@output_buffer.to_sn
ensuren
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffern
endn"
61. Remember how we render our partial?
render partial: "users/hello", locals: { user: @user }
The local_assigns is actually the locals
{ user: @user }
So when we call local variable user in our view, it's actually
searching the key :user's value from the locals hash.
And this mapping is generated during compilation.
62. Then the code section will be generated differently according to the
template's format and handler. In our case we are rendering an erb
file so it's generated by ERB handler.
"def _app_views_users__hello_html_erb___4079420934646067298_70142066674000(local_assigns, output_buffer)n
......
# locals_code
user = user = local_assigns[:user]
# code
@output_buffer = output_buffer || ActionView::OutputBuffer.new;
@output_buffer.safe_append='Hello '.freeze;
@output_buffer.append=( user.name );
@output_buffer.safe_append='!n'.freeze;
@output_buffer.to_sn
ensuren
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffern
endn"
erb uses a buffer to store strings, it keeps appending string into
the buffer and output the final result with to_s method.
63. Now we have a complete method definition in source variable.
Rails will then use module_eval to make mod
(ActionView::CompiledTemplates) evaluate the it, so the module
will have that method.
def compile(mod)
....
mod.module_eval(source, identifier, 0)
...
end
65. This is the simplist phase, Rails just calls the method it defined
and it'll return the result.
def render(view, locals, buffer = nil, &block)
instrument_render_template do
compile!(view)
view.send(method_name, locals, buffer, &block)
end
rescue => e
handle_render_error(view, e)
end
66. To summarize
• Template rendering is a long journey, so it consumes a lot of
computing resources and time.
• Everytime we render a template, Rails creates an
ActionView::Base's instance as an isolated rendering
environment.
• Rails renders templates and partials differently.
67. To summarize
• LookupContext plays a key role in the rendering process since it
holds view paths and details for searching a template.
• A resolver represents a place to look for templates.
• Every template would be compiled into a method once it gets
rendered. So to some degree we can say rendering template is
just calling methods on ActionView::Base's instance.