开发者

Rails3 Cache Sweeper for has_and_belongs_to_many association

I have the foll开发者_JAVA百科owing relationships modeled in a Rails3 application:

class User < ActiveRecord::Base
  has_and_belongs_to_many :skills
end

class SkillsUser < ActiveRecord::Base
end

class Skill < ActiveRecord::Base
  has_and_belongs_to_many :users
end  

The "SkillsUser" model represents the many-to-many association between users and skills. In this way, when a User adds a new Skill, and said Skill already exists in the "skills" table (i.e "Java"), I simply create the relationship between the existing skill and the user in the skills_users table. All good.

Within the User's view, I display a list of Skills. And I have a fragment caching block wrapped around those skills.

<% cache([user,"skills"]) do %>
<div id="skills-grid">
      <% user.sorted_skills.each do |s| %>
        ...
  <% end %>
</div>
<% end %>

On a separate edit page, a User can add or delete a Skill. This action simply creates or removes a skills_users record. And when this happens, I need to invalidate the fragment cache so that the skills render appropriately on the User view.

So I created a CacheSweeper who's purpose in life is to observe the skills_users relationship. Here's the controller:

class SkillsController < ApplicationController
  autocomplete :skill, :name
  cache_sweeper :skill_user_sweeper

  def create
    @user  = User.find(params[:user_id])
    #Make sure the current user has access to 
    #associate a skill to the user in the request
    if(@user.id = current_user.id)
      SkillsHelper.associate_skill(@user,params[:skill][:name])
      @skill  = Skill.find_by_name(params[:skill][:name])
    end
    respond_to do |format|
      format.js
    end
  end

  def destroy
    @skill = Skill.find_by_id(params[:id])
    @user  = User.find_by_id(params[:user_id])
    #Destroy the relationship, not the skill
    @user.skills.delete(@skill) if(@skill.can_be_tweaked_by?(current_user))

    respond_to do |format|
      format.js
    end
   end
end

And here's the sweeper:

class SkillUserSweeper < ActionController::Caching::Sweeper
  observe SkillsUser

  def after_create(skill_user)
    expire_cache_for(skill_user)
  end

  def after_update(skill_user)
    expire_cache_for(skill_user)
  end

  def after_destroy(skill_user)
    expire_cache_for(skill_user)
  end

  private
  def expire_cache_for(skill_user)
    expire_fragment([skill_user.user,"skills"])
  end  
end

The problem is, after adding or removing a skills_users record (after "create" or "destroy" on the SkillsController), the sweeper is never invoked. I have other sweepers working within my project, but none of them observe many-to-many associations.

My question, then, is how does one create a CacheSweeper to observe a "has_and_belongs_to_many" association?


I would try using the user.id rather than user as the key. i.e. change

<% cache([user,"skills"]) do %>

to

<% cache([user.id,"skills"]) do %>

I would also add logger messages inside the callbacks as well as a logger message in the SkillUserSweeper class to make sure it is being loaded.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜