Does Rails cache templates? - ruby-on-rails

I assume yes, and some tests point to yes, but I'd like to find the documentations that says Rails caches (unevaluated) templates in memory.
That is, for any .erb, .sass, .jbuilder, etc template Rails will:
read the template from file, only once
retrieve the template from memory when needed
apply data to the template on every invocation unless the generated output is cached.
All template/cache searches and documentation seem to be focused on point #3. And development Rails flags enable/disable class-caching. But finding docs that verify claim #1/#2 seem illusive. Does Rails re-read template files every time and rely on OS level file caching?

I had the same question and did some hunting.
Yes - Rails caches templates.

Pay attention to the fact cache takes locals as key, and I would say then that unevaluated template is not cached.

In production, it will if you add calls to do so. It is disabled in development mode however you can edit it to cache in development as well in your config/environments/development.rb file by changing the following line from false to true:
config.action_controller.perform_caching = false
In production, Rails has 3 main methods of caching when it comes to views (there are also rails methods for db caching). Page-caching, action-caching, and fragment-caching. To implement these in Rails you can use certain helpers like the caches_page macro-style method in a controller. This will cache the view in its entirety to disk with no further involvement by the Rails dispatcher. This should only be used when the page is completely static and has no dynamic content. caches_action and fragment caching provide much more fine-grained implementations and probably make up the majority of use-cases in Rails.

Related

Revert the results of rails scaffolding in production

When a model is generated in rails - let's say to keep records for users, then we also get a route/controller/view for handling these (CRUD). Therefore visiting "root_url/users" would list all the users, "root_url/users/1" would display the first user etc.
While this is handy in a dev environment, it's not inappropriate for production (currently production for me is Heroku).
I could just remove the extra controllers, views etc. but I was wondering whether there is a standard way of approaching this issue (like a flag in a config file) so that there isn't a mismatch between dev and production.
Yes there is a standard way of approaching this issue, it's called testing, code review, and generellay just doing what is required for your application to work.
Scaffolding code is a good thing, but you just have to use it when it's needed. If you commit often enough, you can scaffold and easily reset what you've done if it does not meet your need.
It is your responsibility to not put any code in production :)

Does Rails re-compile the whole erb/haml view every time some hits it in production?

Say the view is in erb/haml, but is static (doesn't have any dynamic parts within it), does Rails recompile that view every time someone hits it, or does it cache the html after someone hits it once?
A follow up question: if I have a view with some dynamic parts, does Rails recompile only the dynamic part of the view or does it recompile the whole page?
I'm running Rails 4.
Rails evaluates view files and partials on every request. That is why html fragment caching is so valuable.
See Caching with Rails in Rails Guides.
Typically you would use Rails' cache to cache a html fragment so it does not need to be re-rendered on each request. Here's a Haml example:
- cache "key-name-for-static-content" do
.some-html
some content
See DHH's How Key-Based Cache Expiration Works for key-based caching using models.
For advanced uses, I wrote cache_rocket to help cache static content around dynamic content in partials.
Just a bit of terminology note: now compile is commonly referring to the act of turning the view template into a ruby function. Rails does this for all views:
http://guides.rubyonrails.org/action_view_overview.html#template-caching
Those functions will then output the output you want.
So I would say views are not "re-compiled" but "re-evaluated".

Rails app with non-HTTP access

Hypothetical question (at the moment!)
Suppose I have a great idea for an application. It acts on data which can be well-represented by tables in a relational database, using interlinked objects which represent those tables. It supports a well-defined API for interacting with (Creating, Reading, Updating, Deleting) those objects, and viewing information about them.
In short, it's a perfect fit for Rails... except it doesn't want to be a web-app. Perhaps it wants a Command Line interface; or an OS-native dialog-based interface; or perhaps it wants to present itself as a resource to other apps. Whatever - it just isn't designed to present itself over HTTP.
These questions suggest it's certainly possible, but both approach the problem from the point of view of adapting an existing web-app to have an additional, non-web, interface.
I'm interested in knowing what the best way to create such an app would be. Would you be best to rails new non_web_app, in order to get the skeleton built "for free", then write some "normal" Ruby code that requires config/environment - but then you have a lot of web-centric cruft that you don't need? Or would it be better to roll up your sleeves and build it from whole cloth, taking just the libraries you need and manually writing any required configuration?
If the latter, what exactly is needed to make a Rails app, but without the web bits?
If you want to access the Rails ORM to develop a CRUD non-web application, just include ActiveRecord in your own Ruby script; you will avoid using a lot of Rails modules you probably don't need (routing, template generator, ...) Here is an example of how to do it.
If you prefer to have the full Rails stack, do not run your Rails web app in an application server (WEBrick, Passenger, Mongrel, ...) to avoid any HTTP exposure, and interact with your application using tasks or the rails console.
I would avoid taking Rails too far off the rails. If I were doing this and felt that the gains of rails w/o the web stuff I'd do the following:
rails new non_web_app
and ignore the webbish cruft and use rails to generate models. In this way you get the tight, comfortable database behavior and can tie various gems in as you want to augment those models. I'd not bother implementing views, of course, and I'd consider implementing controllers in which the various render bits are removed and to use you instantiate an instance of the controller and call the action directly. This means the controller represents your API into your business logic still but the "views" it now "renders" are simply the return of the data output.
Then you could simply strip out the bits you do not need...the public directory, the view structure under app, config/routes.rb, etc. You'll need to test those changes incrementally and make sure that removing some now extraneous bit doesn't throw the Rails world into chaos.
Rails is for Web apps. That means HTTP. Now, you could package a Web app so that it runs on the desktop instead, or you could use ActiveRecord with a desktop application framework like Monkeybars.

Rails how to edit and save files in browser?

I want to make a CMS where I can edit the view and css files online in my browser.
How can it be done? Does everything have to be in a database?
Generally Stack Overflow is not for research, it's for problem solving. That said…
No, your editable assets do not have to be in a database for this to work.
But you want them to be anyways; allowing write access to the files in your application isn't the best approach.
The rendering chain of Rails 3 allows you to sub in your own view parser and add a path to the built in view-finding that you can trick into loading from a database relatively easily.
Having your end users write in something like Liquid templates will save you a lot of work and allow this to happen with relative ease. They won't have access to unsafe Ruby methods, and you won't have to go through all the work of sandboxing them in Ruby.
CSS has fewer security implications, so you can fairly easily store raw CSS in the database and allow your users to edit it to their liking and then serve it up with a request to a stylesheets/:user_id/style.css request (with some heavy caching, like with Varnish, to save your application from being murdered).
Hopefully that'll get you started out in the right direction. If you decide to hook into the rendering stack in Rails I strongly suggest you pickup a copy of Crafting Rails Applications — one of the handful of example applications it walks you through does just that at a fairly granular level.

Rails page caching with intra-page administration

I'd love to use page caching on a Rails site I run. The information on each page is mostly constant, but the queries that need to be run to collect the information are complicated and can be slow in some cases.The only obstacle to using page caching is that the administrative interface is built into the main site so that admin operations can be performed without leaving the page of interest.
I'm using Apache+mod_rails (Passenger). Is there a way to indicate to Apache that .html files should be ignored when the current user either has a session variable or a cookie named 'admin'*? The session variable need not be evaluated by Apache for validity (since it will be evaluated by Rails in this case).
Is there a way to indicate to Apache that .html files should be ignored when the current user either has a session variable or a cookie named 'admin'*?
I believe it is not really possible. Even if it is, I guess should be very tricky.
Instead you can use Action Caching. A quote from docs:
One of the issues with page caching is
that you cannot use it for pages that
require checking code to determine
whether the user should be permitted
access.
This sounds like exactly your case.
But if you still really need Page Caching via web server, I think you better implement separate pages for admin and non-admin.
This is because of one reason. When you enable Page Caching rails doesn't process the request at all and thus there is no way to know if user is authenticated or not.
You probably can overcome this using Dynamic Page Caching. The idea is basically to add the "admin" part from the JavaScript. I don't personally like this a lot though.
One more update: quick search brought me to this article.
The idea is to cache page conditionally and plug mod_rewrite to serve admin pages.
Will work for you but is pretty dirty solution.

Resources