RubyFlow The Ruby and Rails community linklog

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).

Comments

Amazing stuff! Brilliant idea! Thanks so much for this :-)

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.

Thanks for sharing this great article! That is very interesting Smile I love reading and I am always searching for informative information like this.fxgeorge

@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.

@Bragi, you could use Cells in this case. https://github.com/apotonick/cell

@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 http://m.onkey.org/2010/1/22/active-record-query-interface (chapter “Lazy Loading”). btw. (how) does your plugin handle this situation, Cesario?

@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.

Isn’t New Twitter an example of such paradigm?

@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.

Post a comment

You can use basic HTML markup (e.g. <a>) or Markdown.

As you are not logged in, you will be
directed via GitHub to signup or sign in