RubyFlow : The Ruby Community Blog

Home   Submit   Sign Up   Log In   leaders   Twitter   RSS Feed  

No Querying Views script

I just released a script called No Querying Views. Once installed within the config/initializers directory, it will raise an exception every time one will try to fetch data from the database within a view. I used it to replace ActionController::Base in favor of Michael Sofaer's Vanna::Base, believing "that all web requests should operate as logical clients of a JSON API" (and it was not possible to move until the views were lazy loading data across the application).


Amazing stuff! Brilliant idea! Thanks so much for this :-)Ary Borenszweig - November 03, 2010 00:22
One of the most stupid ideas I have seen.

Imagine you have a sidebar with list of latest links (like on the right in Ruby Flow, look there ->). With this plugin you have to populate this list in each controller.

In controller:

@latest_links = Link.latest

and in view:

- @latest_links.each do |link|
%li= link_to(link.title, link.url)

Another option is to use Link.latest directly in view:

- Link.latest.each do |link|
%li= link_to(link.title, link.url)

And now imagine you want to present cached list. With this plugin you still have to do query in each request - it's done in controller!

When you use Link.latest in you view you can wrap the whole partial in cache block. This not only caches view but also the sql query as well:

- cache("latest_links") do
- Link.latest.each do |link|
%li= link_to(link.title, link.url)

TL;DR: you can and should use tested model class methods, including named scopes, to simplify controllers and to allow simple caching later on. You just need to be smart about it. No plugin can rescue you from your own stupidity.Bragi Ragnarson - November 03, 2010 07:10
Thanks for sharing this great article! That is very interesting Smile I love reading and I am always searching for informative information like this.fxgeorgefxgeorge - November 03, 2010 08:46
@Bragi : thanks for bringing up caching in the discussion.

As I said at the bottom of the post (and I probably should have been more verbose about it): this script was helpful to drop all queries from views that had to be replaced by a JSON-only output to build a RESTful API.

It's also very opinionated about how you want to build your application. In the case you mention, I would have exposed the "latest links" somewhere (like http://myapp/api/links?some_parameters) and accessed it using Javascript calls.

To get back on the caching strategy: you can still use whatever cache you want (Rails' built-in ones or other HTTP caching). But it's gonna be done at the action level.franckverrot - November 03, 2010 09:01
@Bragi, you could use Cells in this case. - November 04, 2010 00:48
@Bragi: use a before_filter to load the list for the sidebar so you don't have to repeat code.
concerning caching: in rails 3 the actual database query _is_ lazy. That's why you can use @Bragi's solution (maybe with a before_filter) and rails would not query the database. see (chapter "Lazy Loading").
btw. (how) does your plugin handle this situation, Cesario?Jan - November 04, 2010 07:30
@Jan : the script doesn't do much, it will just raise an exception any time you're trying to load data from the DB within a view.

If you are using ActiveRecord 3.x and want to bring all the data in memory (either as a big hash, or just with plain ruby objects) before rendering anything, make sure you force the load using .all, .first or .last.

As mentioned in Pratik's post, these calls to .all, .first and .last will return respectively an array, and object or nil, and an object or nil.franckverrot - November 04, 2010 08:09
Isn't New Twitter an example of such paradigm?ncr - November 04, 2010 17:59
@ncr Yes, they focused on delivering a reusable API that exposes JSON fragments and New Twitter is consuming the same API another tier application would consume.franckverrot - November 04, 2010 22:46

Post a Comment

Comment abilities for non registered users are currently deactivated, pending time to add a proper CAPTCHA to solve the escalating spam problem. Sorry!