1

After upgrading CanCan 1.4 to CanCanCan 2.0, I can not anymore cache current_ability into memcached with Dalli.

I got error below :

Cache write: profils/11-20170821121414000000::ability
Marshalling error for key 'development:profils/11-20170821121414000000::ability': can't dump hash with default proc
You are trying to cache a Ruby object which cannot be serialized to memcached.
/usr/local/rvm/gems/ruby-2.4.0@rails5.1.1/gems/dalli-2.7.6/lib/dalli/server.rb:414:in `dump'

I store current_ability in memcached through Dalli by overriding CanCan.Ability::current_ability in app/controllers/application_controller.rb

 def current_ability
     Rails.cache.fetch("#{current_user.profil.cache_key}::ability") do
       super
     end
 end

Why I store current_ability in cache ?

cancan slowing down page loads, Because I have a lot of custom actions in many controllers, each page reload all abilities...

Any pointers in regards to cacheing / optimizing / best practices would be most appreciated. Thanks!

update 1

Add app/models/ability.rb

class Ability
   include CanCan::Ability

   def initialize(user)
     alias_action :edit, :to => :read
     role = user.profil

     if role.label == 'administrateur'
       can :manage, :all
     else
       role.rights.each do |right|
         model = right.resource.constantize rescue nil
         next unless model
         [:read, :create, :update, :destroy].each do |capability|
           can capability, model if right.send("#{capability}?")
         end
       end
       # Custom actions
       can([:collective, :collective_week, :presence, :day_details, :day_details_json], Movement) if can?(:read, Movement)
       can(:quick_add, Movement) if can?(:create, Movement)
       can([:actions, :set_action, :choose, :previous, :families_addresses, :ios,:families_members,:potential_relationships,:list_families,:list_decisions], Person) if can?(:read, Person)
       can(:addresses, Family) if can?(:read, Family)
       ...
       ...
       ...
     end
   end
end

Update 2

Print an object of Ability (below is just a snippet of ability but the stucture is the same) That's the data that I try to store in memcached :

#<Ability:0x000000093030a0
 @aliased_actions={:read=>[:index, :show, :edit], :create=>[:new], :update=>[:edit]},
 @expanded_actions=
  {[:index, :show, :edit]=>[:index, :show, :edit]},
 @rules=
  [#<CanCan::Rule:0x00000008fb3e18
    @actions=[:read],
    @base_behavior=true,
    @block=nil,
    @conditions={},
    @match_all=false,
    @subjects=[AcceptanceReason(id: integer, label: string, created_at: datetime, updated_at: datetime, institution_position: integer, acceptance_number: integer, department_type_id: integer)]>,
   #<CanCan::Rule:0x00000008fb3760
    @actions=[:create],
    @base_behavior=true,
    @block=nil,
    @conditions={},
    @match_all=false,
    @subjects=[AcceptanceReason(id: integer, label: string, created_at: datetime, updated_at: datetime, institution_position: integer, acceptance_number: integer, department_type_id: integer)]>],
 @rules_index=
  {AcceptanceReason(id: integer, label: string, created_at: datetime, updated_at: datetime, institution_position: integer, acceptance_number: integer, department_type_id: integer)=>[0, 1, 2, 3],
   Activity(id: integer, created_at: datetime, updated_at: datetime, institution_id: integer, label: string, activity_type_id: integer, employee_id: integer, department_id: integer, group_id: integer, beginning_at: date, ending_at: date, location: text, comments: text, objectif: text, evaluation: text, colour: string, collective_intervention_mean_id: integer, collective_intervention_status_id: integer, archive: boolean, activity_beginning_time: time, activity_ending_time: time, moyens_materiels: text, transports: text, autres_intervenants: text, budget: text, frequency: string)=>
    [4, 5, 6, 7, 645],
   ActivityCode(id: integer, label: string, created_at: datetime, updated_at: datetime)=>[8, 9, 10]}
孙悟空
  • 1,215
  • 1
  • 11
  • 26
  • Why do you use an instance variable there? Try `def current_ability; Rails.cache.fetch(...) { super }; end` – xlembouras Aug 21 '17 at 14:35
  • Even I remove the instance variable, the same error is always there. – 孙悟空 Aug 21 '17 at 14:49
  • can you provide your ability initialization? maybe its return value is not serializable and that causes the error. – xlembouras Aug 21 '17 at 14:58
  • @xlembouras, Thank you for your attention, I updated my question. – 孙悟空 Aug 21 '17 at 15:07
  • I can't see something wrong... Make sure you reload your environment. Restart spring, rails server and memcached in case there is something broken there. If that doesn't work, try to manually marshal dump and load ( https://stackoverflow.com/questions/18849482/can-can-selectively-cache-abilities ) – xlembouras Aug 21 '17 at 15:18
  • interesting, can you also print the content of ability `rules`? – coorasse Aug 22 '17 at 06:13
  • @coorasse, Thank you for your attention, I updated my question – 孙悟空 Aug 22 '17 at 07:55

0 Answers0