Sunday, April 24, 2016

rails 5 hstore hash

Rails 5 now returns params as a class instance, no longer a hash.
due to the requirement to have random hashs key based on user input,
the only way to do this is to force this value by calling .to_unsafe_h

example:
res = params.require(:detail).permit(:name, :year)
res[:specification] = params[: detail][:specification].to_unsafe_h

but if you do know your hash key, call this instead:
permit(:specification => { :keyname1, keyname2 }

if you have any suggestion, please comment :)

https://forum.upcase.com/t/rails-doesnt-recognize-a-request-as-patch/5115

http://eileencodes.com/posts/actioncontroller-parameters-now-returns-an-object-instead-of-a-hash/

Tuesday, April 12, 2016

speed up rails development

One of the main concern with rails development is the speed.
its very slow indeed when your stack grows.

I found several reasons for it to be slow:

  1. assets, when debug is enabled, each individual js and css file will be loaded individually
  2. navigation menu with permission triggers query and outputting links to admin requires some loading time
  3. crud - list and read is rendered everytime even though record is not updated, this can save more time
  4. sassc - compiling and loading sass is very slow in ruby

1. Assets

If you aren't planning to debug any scripting or css, set
config.assets.debug = false # set this to false if you dont plan to debug your css or js
config.assets.digest = true # this recommended permanently to allow cache on browser


2. Navigation menu

Navigation menu via cancancan gem requires some query to the database. Often this file is not changed frequently, its almost once setup, its forgotten. Therefore it make sense to cache this file based on user session. One way todo this is to cache this based on template name with prefix and current user id.

example:
views/layout/admin/_nav.html.slim
- cache("template_layout_admin_nav_#{current_user.id rescue 0}") do 
  nav. ...
     ... (more code here)

3. List & read

Since most record will not be changed, it make sense to cache each individual view fragment for respective model to be cached. They call this russian doll caching. Rails cache is smart enough to update cache when model updated_at changes. This can be applied to both listing and show.

example listing template:

tbody
  - @rows.each do |row|
    - cache row do
      td = row.id
      td ...

example show template:
- cache @record do
  .panel-body.resource.box.p-a
    .row
      .col-md-12
        = @record.id

4. Use sassc

Sass compilation on rails is slow. Recently, we have found an alternative for faster sass compilation. Make use of sassc, add this into Gemfile.
gem 'sassc-rails', group: [:development, :test, :staging]

It is not recommended to run assets precompile on production server. Its slow and takes a long time to update on server. One way to do this is to compile assets locally.

Before every deployment, run this to update your assets. But because we do not wish to load static assets on our development, add this to config/environment/development.rb
config.assets.prefix = '/dev-assets'

in config/application.rb
config.assets.initialize_on_precompile = false # this ensure local assets precompile for production works without the need to connect to production database

This configuration ensure all assets is delivered via dev-assets on local development, while production assets is generated into public/assets and retrieved via /assets

To compile assets for production, run this:
export RAILS_ENV=production; bundle exec rake assets:precompile

If you have relative uri to your rails instance, call this:
export RAILS_ENV=production; export RAILS_RELATIVE_URL_ROOT=/shop; bundle exec rake assets:precompile
# where /shop = uri to your site

To enable cache in development

in config/environment/development.rb,
config.action_controller.perform_caching = true
config.cache_store = :file_store, Rails.root.join('tmp', 'cache'), { size: 64.megabytes }
# config.cache_store = :memory_store, { size: 64.megabytes }
    config.public_file_server.headers = {
      'Cache-Control' => 'public, max-age=172800'
    }

It is recommended to set cache memory_store, so that every time you wish to clear cache, simply restart the rails instance. But if you want to have it persistant on every time, use file_store cache.
But if you ever change the template file in navigation, you will need to clear the cache directory
rm -Rf tmp/cache/#
# = represent the cached folder (ls -lat to get the current directory name)



For further speed tuning, please follow the instruction below:
https://www.nateberkopec.com/2015/08/05/rack-mini-profiler-the-secret-weapon.html