Showing posts with label less. Show all posts
Showing posts with label less. Show all posts

Monday, March 10, 2014

Caching Simple Navigation

Morale: Simple Navigation is not that simple

We, in our firm, have different types of user navigation for different types of users. We wanted the flexibility of creating our navigation from the backend(rails) so that there is just one file to maintain with all configurations. Simple Navigation works great in this aspect.

The configuration is complex, but is absolutely generic. We have a couple of navigations to start with, for the normal application and when a user visits the application via the iPad.

The navigation for the normal user takes more than 500ms to render. NOT GOOD! We decided on caching the html. For this we need to split the navigation yet again. With respect to logged in users. Therefore we now have 4 types of navigation, loggedout-normal, loggedin-normal, loggedout-iPad, loggedin-iPad.

We also had some badges on the navigation for unopened items. The next step was to remove these from the navigation file. We created a notifications controller and wrote a small javascript, which takes data from the json response of the show method of this controller, and updated the corresponding sections in the navigation.

Now came the hard part. Caching.

We need to define keys for the Caching itself first.

For a logged out normal user, this would be quite straight forward. Get the locale of the navigation bar. All the users with the same locale got the same navigation bar.

For logged out normal users it would be a little tricky. We have some user specific stuff in the navigation bar such as the username. Therefore, we need the user_id. The user could change his locale and this would trigger a change in the updated_on field on the Users table. This would mean that we need to include this in the key as well. We have a specific link for backend services if the user has admin privileges. For this we need to evaluate the roles of the user. An MD5 has been used to facilitate this.

We need to Cache the non highlighted navigation bar for sanity purposes. Then we plan to highlight the section according to the pages that are rendered. For this we could either create a javascript to add the correct classes or create a stylesheet which highlights the correct section on verification of the correct classes.

We decided to create a stylesheet for this. The stylesheet reads the configuration from the simple_navigation configuration and creates the correct CSS. The file is a LESS file. We extracted the styles to highlight the navigation items into some mixins and used these mixins inside our custom classes.

The next tough part is the sub navigation. While this problem still lurks, we are trying to get away from the sub navigation altogether.

While this post is clearly not technical and is conceptual, this might help some others trying to solve something similar to this.

:)

Friday, March 15, 2013

Less Caching

We came across this unusual problem when developing. So for starters, there is a Gem that we use and a test application reside in the test folder of the Gem. The Gem uses only Javascript in the app/assets folder and has a minimal Ruby code.

The Gem uses Bootstrap's less version to set the CSS. We use the mixins by Bootstrap and overwrite variables and stuff. The Gem still used SASS and we felt a little odd with writing mixed CSS. Therefore we moved all the stuff to less files and put it all in assets/stylesheets. Nice and organized. 

Now we had the problem. We made a change to the less files and the application did not load them. We had put all our imports in a main file and any change to the main file reflected in the test app. but not if the change were done inside the individual imports.

We wanted to analyze if the problem was with Sprockets or with less-rails. After some probe and hunt we concluded that the problem indeed was with less-rails. The Gem caches the imports which prevent any compilation after the import to the base file (first level).

I tried adding options like

config.consider_all_requests_local = true config.action_controller.perform_caching = false 

inside the environment files, but alas! no change what so ever.

So we had to do the inevitable. Look at files and trigger a restart and cache clear.

The process was to be something like :

if Change? 
  rake tmp:clear 
  powder restart (or touch tmp/restart) [we use pow]

Guard was perfect for this.

2 Guard plugins were used for this :
  guard-process => To run the rake process
  guard-pow => To restart Pow

The file looked something like this

# RUN bundle exec guard -p -i -w ../../ 
guard 'pow' do 
 watch(%r{app/assets/stylesheets/**/.*\.less$}) 
end 

guard 'process', :name => 'ClearCache', :command => 'rake tmp:clear' do
 watch(%r{app/assets/stylesheets/**/.*\.less$}) 
end 

The guard command needed to run with
  -w because we were looking at a change from another directory
  -p for polling
  -i for no interactions

phew..