Skip to content

Instantly share code, notes, and snippets.

@jhjguxin
Created July 12, 2012 18:54
Show Gist options
  • Save jhjguxin/3100116 to your computer and use it in GitHub Desktop.
Save jhjguxin/3100116 to your computer and use it in GitHub Desktop.
How BBTangCMS use cancan include (Role Based Authorization, Non RESTful Controllers Authorization, Admin Namespace Action Aliases, Abilities in Database)
class Ability
include CanCan::Ability
def initialize(user, controller_namespace)
alias_action :index, :show, :to => :read
alias_action :new, :to => :create
alias_action :edit, :to => :update
#destroy, update ,create
@user = user || User.new # for guest
case controller_namespace
when 'auth'
#can :manage, :all if self.limit_admin_group?
can :read, :all if @user.limit_admin_group?
else
# rules for non-admin controllers here
end
case controller_namespace
when 'admin'
#can :manage, :all if self.limit_admin_group?
can :read, :all if @user.limit_admin_group?
else
# rules for non-admin controllers here
end
# Checking Abilities from cms_roles
@user.cms_roles.each { |role| send(role.name.downcase) if (role.present? and self.respond_to? role.name.downcase) }
=begin
@user.cms_roles.each do |cr|
cr.cms_role_permits.each do |crp|
send(crp.permit.name.downcase) if (crp.permit.present? and self.respond_to? crp.permit.name.downcase)
end
end
@user.permits.each { |permit| send(permit.name.downcase) if (permit.present? and self.respond_to? permit.name.downcase) }
=end
#@user.cms_permits_all.each { |permit| send(permit.name.downcase) if (permit.present? and self.respond_to? permit.name.downcase) }
#if @user.cms_roles.size == 0
if @user.cms_roles.empty?
#can :read, :all #for guest without roles
cannot :manage, :all
else
#FIXME Nested Resources canot soveld because many special date must been supplied
# eg: http://localhost:3000/tag/identities/838/timelines/839/categories/840
if controller_namespace.present?
if %w(tag quiz_center).include? controller_namespace
check_ability_from_all_permit(user)
elsif controller_namespace.eql? "auth"
#do nothing
end
else
can do |action, subject_class, subject|
#因为匿名 subject_class 的一些授权是没有存放在数据库的
unless subject_class.name.eql? "Symbol"
can_accessible = false
#aliases_for_action(action) =>[:index, :read]
aliase_action = aliases_for_action(action).last
class_name = subject_class.name.underscore.gsub("/","_")
#eg index_tag_identity
permit_name = [aliase_action, class_name].collect{|item| item if item.present?}.compact.join("_")
#eg index_identity
permit_name_nonamespace = [aliase_action, class_name].collect{|item| item if item.present?}.join("_")
#eg read_tag_identity
permit_name_aliase_action = [action, controller_namespace, class_name].collect{|item| item if item.present?}.compact.join("_")
#eg read_identity
permit_name_aliase_action_nonamespace = [action, class_name].collect{|item| item if item.present?}.join("_")
# check_abilit
if (can_accessible = user.has_permit?(permit_name))
#check_ability_by_permit_name(@user, permit_name)
elsif (can_accessible = user.has_permit?(permit_name_nonamespace))
#check_ability_by_permit_name(@user, permit_name_nonamespace)
elsif (can_accessible = user.has_permit?(permit_name_aliase_action))
#check_ability_by_permit_name(@user, permit_name_aliase_action)
elsif (can_accessible = user.has_permit?(permit_name_aliase_action_nonamespace))
#check_ability_by_permit_name(@user, permit_name_aliase_action_nonamespace)
end
can_accessible
end
end
end
end
end
def check_ability_by_permit_name(user,permit_name)
user ||= User.new
if permit_name.present?
permit = user.find_cms_permit_by_name(permit_name)
#send(permit.name.downcase) if (permit.present? and self.respond_to? permit.name.downcase)
true if permit.present?
else
false
end
end
def check_ability_from_all_permit(user)
user ||= User.new
user.cms_permits_all.each { |permit| send(permit.name.downcase) if (permit.present? and self.respond_to? permit.name.downcase) }
end
##################create ##########################
def create_profile
can :create, Profile
end
def create_knowledge
can :create, Knowledge
end
def create_news
can :create, News
end
def create_category_base
can :create, CategoryBase
end
def create_subject
can :create, Subject
end
def create_attachment
can :create, Attachment
end
def create_question
can :create, Question
can [:update_timelines, :update_categories] , Question
end
def create_question_answer
can :create, Answer#, :question => Question.new
end
def create_tag_identity
can :create, Identity
end
def create_tag_identities_timeline
# can :manage, Category, :restaurant => {:user_id => user.id}
can :create, Timeline
end
def create_tag_identities_timelines_category
#debugger
can :create, Category#, :identity => Identity.new, :timeline => Timeline.new
end
def create_recommend_recommend_app
can :create, Recommend::RecommendApp
end
def create_recommend_recommend_event
can :create, Recommend::RecommendEvent
end
def create_recommend_recommend_mtool
can :create, Recommend::RecommendMtool
end
def create_recommend_recommend_product
can :create, Recommend::RecommendProduct
end
def create_recommend_recommend_question
can :create, Recommend::RecommendQuestion
end
def create_recommend_recommend_quiz
can :create, Recommend::RecommendQuiz
end
def create_recommend_recommend_subject
can :create, Recommend::RecommendSubject
end
def create_recommend_recommend_tag
can :create, Recommend::RecommendTag
end
def create_recommend_recommend_user
can :create, Recommend::RecommendUser
end
def create_recommend_recommend_hindex
can :create, Recommend::RecommendHindex
end
def create_recommend_recommend_ptag
can :create, Recommend::RecommendPtag
end
def create_recommend_expert_category
can :create, Recommend::ExpertCategory
end
def create_recommend_vip_category
can :create, Recommend::VipCategory
end
def create_recommend_recommend_other
can :create, Recommend::RecommendOther
end
def create_recommend_other_column
can :create, Recommend::OtherColumn
end
def create_quiz_center_quiz
can :create, Quiz
end
def create_quiz_center_quiz_collection
can :create, QuizCollection
end
def create_work_contact
can :create, Contact
end
##################update ##########################
def update_profile
can :update, Profile
end
def update_knowledge
can :update, Knowledge
end
def update_news
can :update, News
end
def update_category_base
can :update, CategoryBase
end
def update_subject
can :update, Subject
end
def update_attachment
can :update, Attachment
end
def update_question
can :update, Question
can [:update_timelines, :update_categories] , Question
end
def update_note
can :update, Note
end
def update_question_answer
can :update, Answer#, :question => Question.new
end
def update_tag_identity
can :update, Identity
end
def update_tag_identities_timeline
can :update, Timeline => Identity#, :identity => Identity.new
end
def update_tag_identities_timelines_category
can :update, Category#, :identity => Identity.new, :timeline => Timeline.new
end
def update_recommend_recommend_app
can :update, Recommend::RecommendApp
end
def update_recommend_recommend_event
can :update, Recommend::RecommendEvent
end
def update_recommend_recommend_mtool
can :update, Recommend::RecommendMtool
end
def update_recommend_recommend_product
can :update, Recommend::RecommendProduct
end
def update_recommend_recommend_question
can :update, Recommend::RecommendQuestion
end
def update_recommend_recommend_quiz
can :update, Recommend::RecommendQuiz
end
def update_recommend_recommend_subject
can :update, Recommend::RecommendSubject
end
def update_recommend_recommend_tag
can :update, Recommend::RecommendTag
end
def update_recommend_recommend_user
can :update, Recommend::RecommendUser
end
def update_recommend_recommend_hindex
can :update, Recommend::RecommendHindex
end
def update_recommend_recommend_ptag
can :update, Recommend::RecommendPtag
end
def update_recommend_expert_category
can :update, Recommend::ExpertCategory
end
def update_recommend_vip_category
can :update, Recommend::VipCategory
end
def update_recommend_recommend_other
can :update, Recommend::RecommendOther
end
def update_recommend_other_column
can :update, Recommend::OtherColumn
end
def update_quiz_center_quiz
can :update, Quiz
end
def update_quiz_center_quiz_collection
can :update, QuizCollection
end
def update_work_contact
can :update, Contact
end
##################read ##########################
def read_profile
can :read, Profile
end
def read_knowledge
can :read, Knowledge
end
def read_news
can :read, News
end
def read_category_base
can :read, CategoryBase
end
def read_subject
can :read, Subject
end
def read_attachment
can :read, Attachment
end
def read_question
can :read, Question
end
def read_note
can :read, Note
end
def read_question_answer
can :read, Answer#, :question => Question.new
end
def read_tag_identity
can :read, Identity
end
def read_tag_identities_timeline
can :read, Timeline#, :identity => Identity.new
end
def read_tag_identities_timelines_category
can :read, Category#, :identity => Identity.new, :timeline => Timeline.new
end
def read_recommend_recommend_app
can :read, Recommend::RecommendApp
end
def read_recommend_recommend_mtool
can :read, Recommend::RecommendMtool
end
def read_recommend_recommend_product
can :read, Recommend::RecommendProduct
end
def read_recommend_recommend_question
can :read, Recommend::RecommendQuestion
end
def read_recommend_recommend_quiz
can :read, Recommend::RecommendQuiz
end
def read_recommend_recommend_subject
can :read, Recommend::RecommendSubject
end
def read_recommend_recommend_tag
can :read, Recommend::RecommendTag
end
def read_recommend_recommend_user
can :read, Recommend::RecommendUser
end
def read_recommend_recommend_hindex
can :read, Recommend::RecommendHindex
end
def read_recommend_recommend_ptag
can :read, Recommend::RecommendPtag
end
def read_work_contact
can :read, Contact
end
def read_recommend_expert_category
can :read, Recommend::ExpertCategory
end
def read_recommend_vip_category
can :read, Recommend::VipCategory
end
def read_recommend_recommend_other
can :read, Recommend::RecommendOther
end
def read_recommend_other_column
can :read, Recommend::OtherColumn
end
def read_quiz_center_quiz
can :read, Quiz
end
def read_quiz_center_quiz_collection
can :read, QuizCollection
end
##################destroy ##########################
def destroy_profile
can :destroy, Profile
end
def destroy_knowledge
can :destroy, Knowledge
end
def destroy_news
can :destroy, News
end
def destroy_category_base
can :destroy, CategoryBase
end
def destroy_subject
can :destroy, Subject
end
def destroy_attachment
can :destroy, Attachment
end
def destroy_question
can :destroy, Question
end
def destroy_note
can :destroy, Note
end
def destroy_question_answer
can :destroy, Answer#, :question => Question.new
end
def destroy_tag_identity
can :destroy, Identity
end
def destroy_tag_identities_timeline
can :destroy, Timeline#, :identity => Identity.new
end
def destroy_tag_identities_timelines_category
can :destroy, Category#, :identity => Identity.new, :timeline => Timeline.new
end
def destroy_recommend_recommend_app
can :destroy, Recommend::RecommendApp
end
def destroy_recommend_recommend_mtool
can :destroy, Recommend::RecommendMtool
end
def destroy_recommend_recommend_product
can :destroy, Recommend::RecommendProduct
end
def destroy_recommend_recommend_question
can :destroy, Recommend::RecommendQuestion
end
def destroy_recommend_recommend_quiz
can :destroy, Recommend::RecommendQuiz
end
def destroy_recommend_recommend_subject
can :destroy, Recommend::RecommendSubject
end
def destroy_recommend_recommend_tag
can :destroy, Recommend::RecommendTag
end
def destroy_recommend_recommend_user
can :destroy, Recommend::RecommendUser
end
def destroy_recommend_recommend_hindex
can :destroy, Recommend::RecommendHindex
end
def destroy_recommend_recommend_ptag
can :destroy, Recommend::RecommendPtag
end
def destroy_recommend_expert_category
can :destroy, Recommend::ExpertCategory
end
def destroy_recommend_vip_category
can :destroy, Recommend::VipCategory
end
def destroy_recommend_recommend_other
can :destroy, Recommend::RecommendOther
end
def destroy_recommend_other_column
can :destroy, Recommend::OtherColumn
end
def destroy_quiz_center_quiz
can :destroy, Quiz
end
def destroy_quiz_center_quiz_collection
can :destroy, QuizCollection
end
def destroy_work_contact
can :destroy, Contact
end
##############other permit
def resetscore_question
can :resetscore, Question
end
##################other ##########################
#def editor
# can :manage, Employee
#end
#def operatoradmin
# can :manage, Employee
#end
#def operator
# can :manage, Employee
#end
def admin
#manager
#include User,CmsRole
can :manage, :all
end
def guest
basic_ability
end
protected
def basic_ability
#can [:index,:destroy,:show] , User
#can :index, Product
#can :show, Product
can :manage, :dashboard
can :read , Version
can [:index,:item_list,:search_tag], :archive
can :index, :hot_tags
# bellow is defining for "Tag::DashboardController " any it work as follow line(cancan 1.6.7)
#and also shuld same with auth/dashboard but I filter, with another method
can :show, :dashboard
can :search, :common
can :lastest_log, :common
end
#def initialize(user)
# Define abilities for the passed in user here. For example:
#
# user ||= User.new # guest user (not logged in)
# if user.admin?
# can :manage, :all
# else
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user permission to do.
# If you pass :manage it will apply to every action. Other common actions here are
# :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on. If you pass
# :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
#
# The third argument is an optional hash of conditions to further filter the objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
#end
end

route you can use

#routes.rb
BBTangCMS::Application.routes.draw do
  namespace :auth do
    resources :users
    resources :cms_roles
    resources :assign_permits
    root :to => 'dashboard#show', :as => :dashboard
  end
end

add role to user

#auth/users_controller.rb
class Auth::UsersController < Auth::AuthBaseController
  load_and_authorize_resource
  Model_class = User.new.class
  
  # PUT /auth/users/1
  # PUT /auth/users/1.json
  def update
    #@auth_user = Auth::User.find(params[:id])

    @auth_user = User.find(params[:id])
    @auth_user.update_user_permit(params[:user][:cms_role_ids]) if params[:user].key? :cms_role_ids
    respond_to do |format|
      if @auth_user.update_attributes(params[:user])

        format.html { redirect_to auth_user_path(@auth_user), notice: 'User was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @auth_user.errors, status: :unprocessable_entity }
      end
    end
  end
end
#auth/users/edit.html.erb
<%- model_class = @auth_user.class -%>
<div class="page-header">
  <h1><%=t '.title', :default => t('helpers.titles.edit', :model => model_class.model_name.human,
                                   :default => "Edit #{model_class.model_name.human}") %></h1>
</div>

<%= simple_form_for([:auth,@auth_user]) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :username %>
    <%= f.input :email %>
    <!--%= f.input :password, :as => :password %-->
    <%= f.input :confirmation_now, :as => :boolean, :input_html => {:checked =>  @auth_user.confirmed? ? "checked" : ""} %>
    <%= f.association :cms_roles, :as => :check_boxes, :collection => CmsRole.all(:order => 'name'), :checked => ( @auth_user.cms_roles.map(&:id) if @auth_user.cms_roles.present?) %>

  </div>

  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary', :disable_with => 'loading...' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                auth_users_path, :class => 'btn' %>
  </div>
<% end %>

add permit to cms_roles

#auth/cms_roles_controller.rb
class Auth::CmsRolesController < Auth::AuthBaseController
  load_and_authorize_resource
  Model_class = CmsRole.new.class
  # GET /auth/cms_roles
  # GET /auth/cms_roles.json
  def index
    @auth_cms_roles = CmsRole.paginate(:page => params[:page]).order('id DESC')

    breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), auth_cms_roles_path
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @auth_cms_roles }
    end
  end

  # GET /auth/cms_roles/1
  # GET /auth/cms_roles/1.json
  def show
    @auth_cms_role = CmsRole.find(params[:id])

    breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), auth_cms_role_path(@auth_cms_role)
    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @auth_cms_role }
    end
  end

  # GET /auth/cms_roles/new
  # GET /auth/cms_roles/new.json
  def new
    @auth_cms_role = CmsRole.new

    breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), new_auth_cms_role_path

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @auth_cms_role }
    end
  end

  # GET /auth/cms_roles/1/edit
  def edit
    @auth_cms_role = CmsRole.find(params[:id])

    breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), edit_auth_cms_role_path(@auth_cms_role)
  end

  # POST /auth/cms_roles
  # POST /auth/cms_roles.json
  def create
    @auth_cms_role = CmsRole.new(params[:cms_role])

    respond_to do |format|
      if @auth_cms_role.save
        format.html { redirect_to auth_cms_role_path(@auth_cms_role), notice: 'Cms role was successfully created.' }
        format.json { render json: @auth_cms_role, status: :created, location: @auth_cms_role }
      else
        format.html { render action: "new" }
        format.json { render json: @auth_cms_role.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /auth/cms_roles/1
  # PUT /auth/cms_roles/1.json
  def update
    @auth_cms_role = CmsRole.find(params[:id])
    @auth_cms_role.set_cms_role_permits_list(params["cms_role"]["cms_role_permit_ids"]) if params["cms_role"]["cms_role_permit_ids"].present?
    @auth_cms_role.set_assign_permits_list(params["cms_role"]["assign_permit_ids"]) if params["cms_role"]["assign_permit_ids"].present?

    @auth_cms_role.name = params["cms_role"]["name"]

    respond_to do |format|
      if @auth_cms_role.save
        format.html { redirect_to auth_cms_role_path(@auth_cms_role), notice: 'Cms role was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @auth_cms_role.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /auth/cms_roles/1
  # DELETE /auth/cms_roles/1.json
  def destroy
    @auth_cms_role = CmsRole.find(params[:id])
    @auth_cms_role.destroy

    respond_to do |format|
      format.html { redirect_to auth_cms_roles_url }
      format.json { head :no_content }
    end
  end
end
#auth/cms_roles/_form.html.erb
<%= simple_form_for([:auth,@auth_cms_role]) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :name %>

    <% assign_permits = @auth_cms_role.assign_permits.collect {|assign_permit| assign_permit.permit}.compact %>
    <% cms_role_permits = @auth_cms_role.cms_role_permits.collect {|cms_role_permit| cms_role_permit.permit}.compact %>

    <%= f.association :cms_role_permits, :as => :check_boxes, :collection => Permit.all(:order => 'name'),:checked => ( cms_role_permits.map(&:id) if cms_role_permits.present?), :prompt => "Choose a permit" %>
    <%= f.association :assign_permits, :as => :check_boxes, :collection => Permit.all(:order => 'name'), :checked => ( assign_permits.map(&:id) if assign_permits.present?), :prompt => "Choose a permit" %>
  </div>

  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary', :disable_with => 'loading...' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                auth_cms_roles_path, :class => 'btn' %>
  </div>
<% end %>

assign permit to some admin's owner users

#assign_permits_controller.rb
class Auth::AssignPermitsController < Auth::AuthBaseController
  authorize_resource :class => false
  Model_class = CuPermit.new.class
  # GET /auth/assign_permits
  # GET /auth/assign_permits.json
  def index
    if current_user.admin_group?
      @admin_user = current_user

      breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), auth_assign_permits_path
      respond_to do |format|
        format.html # index.html.erb
        format.json { render json: @admin_user }
      end
    end
  end

  # GET /auth/assign_permits/1
  # GET /auth/assign_permits/1.json
  def show
    #@auth_assign_permit = Auth::AssignPermit.find(params[:id])
    @owner_user = User.find(params[:id])
    if params["admin_group"]
      if current_user.owner_users(params["admin_group"]).include? @owner_user
        breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), auth_assign_permit_path(@owner_user)
      end
    end

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @owner_user }
    end
  end

  # GET /auth/assign_permits/new
  # GET /auth/assign_permits/new.json
  def new
    @auth_assign_permit = Auth::AssignPermit.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @auth_assign_permit }
    end
  end

  # GET /auth/assign_permits/1/edit
  def edit
    #@auth_assign_permit = Auth::AssignPermit.find(params[:id])
    if current_user.admin_group?
      @admin_user = current_user
      @owner_user = User.find(params[:id])
      breadcrumbs.add I18n.t("helpers.titles.#{current_action}", :model => Model_class.model_name.human), edit_auth_assign_permit_path(@owner_user)
      respond_to do |format|
        format.html # index.html.erb
        format.json { render json: @admin_user }
      end
    end

  end

  # POST /auth/assign_permits
  # POST /auth/assign_permits.json
  def create
    @auth_assign_permit = Auth::AssignPermit.new(params[:auth_assign_permit])

    respond_to do |format|
      if @auth_assign_permit.save
        format.html { redirect_to @auth_assign_permit, notice: 'Assign permit was successfully created.' }
        format.json { render json: @auth_assign_permit, status: :created, location: @auth_assign_permit }
      else
        format.html { render action: "new" }
        format.json { render json: @auth_assign_permit.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /auth/assign_permits/1
  # PUT /auth/assign_permits/1.json
  def update
    #@auth_assign_permit = Auth::AssignPermit.find(params[:id])
    if current_user.admin_group?
      @admin_user = current_user
      @owner_user = User.find(params[:id])

      respond_to do |format|
        if @owner_user.update_attributes(params[:user])
          format.html { redirect_to auth_assign_permit_path(@owner_user), notice: 'Assign permit was successfully updated.' }
          format.json { head :no_content }
        else
          format.html { render action: "edit" }
          format.json { render json: @auth_assign_permit.errors, status: :unprocessable_entity }
        end
      end
    end
  end

  # DELETE /auth/assign_permits/1
  # DELETE /auth/assign_permits/1.json
  def destroy
    if current_user.admin_group?
      @admin_user = current_user
      @owner_user = User.find(params[:id])
    #@auth_assign_permit = Auth::AssignPermit.find(params[:id])
    #@auth_assign_permit.destroy
      @owner_user.permits = []
      @owner_user.save
      respond_to do |format|
        format.html { redirect_to auth_assign_permits_url }
        format.json { head :no_content }
      end
    end
  end
end
#auth/assign_permits/index.html.erb
<%- model_class = CuPermit.new.class -%>
<%- admin_model_class = User.new.class -%>
<h1><%=t '.title', :default => model_class.model_name.human.pluralize %></h1>
<% if @admin_user.admin_group.present? %>
  <% @admin_user.admin_group.each do |admin| %>
    <h2><%= admin.name %></h2>
    <table class="table table-striped">
      <tr>
        <th><%= admin_model_class.human_attribute_name(:id) %></th>
        <th><%= admin_model_class.model_name.human %></th>
        <th><%= admin_model_class.human_attribute_name(:cms_roles) %></th>
        <!--th><%# admin_model_class.human_attribute_name(:permits) %></th-->
        <th><%=t '.actions', :default => t("helpers.actions") %></th>
      </tr>
      <%- indicates = true %>
      <% @admin_user.owner_users(admin.name.to_s).each do |owner_user| %>
        <tr class=<%= (indicates =!indicates) ? "success" : "info"%>>
        <td><%= link_to owner_user.id, auth_assign_permit_path(owner_user) %></td>
          <td><%= owner_user %></td>
          <td><%= owner_user.cms_roles.map(&:name) %></td>
          <!--td><%# owner_user.permits.map(&:name)%></td-->
          <td><%= link_to t('.show', :default => t("helpers.links.show", :model => model_class.model_name.human)), auth_assign_permit_path(owner_user), :class => 'btn' %>
              <%= link_to t('.edit', :default => t("helpers.links.edit", :model => model_class.model_name.human)), edit_auth_assign_permit_path(owner_user), :class => 'btn' %>
<!--%= link_to t('.destroy', :default => t("helpers.links.destroy", :model => model_class.model_name.human)), auth_assign_permit_path(owner_user,:admin_group => admin.name ),
              :method => 'delete',
              :confirm => t('.confirm',
              :default => t("helpers.links.confirm", :default => 'Are you sure?')),
              :class => 'btn btn-danger' %-->
              </td>
        </tr>
      <% end %>
    </table>
  <% end %>
<% end %>
#auth/assign_permits/_form.html.erb
<%= simple_form_for([:auth,@owner_user], :url =>auth_assign_permit_path(@owner_user), :html => { :class => ".form-horizontal" }) do |f| %>
  <%= f.error_notification %>
  <%= f.input :email do %>
    <%= @owner_user.email %>
  <% end %>

  <div class="form-inputs">
    <%= f.association :permits do %>
      <% if @admin_user.present? %>
        <% @admin_user.cms_roles.each do |cms_role| %>
          <%= cms_role%>
          <%= f.association :permits, :as => :check_boxes, :collection => @admin_user.admin_assign_permits(cms_role),:checked => ( @owner_user.permits.map(&:id) if  @owner_user.permits.present?) %>
        <% end %>
      <% end %>
    <% end %>
  </div>


  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary', :disable_with => 'loading...' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                auth_assign_permits_path, :class => 'btn' %>
  </div>
<% end %>
#auth/assign_permits/show.html.erb
<%- model_class = CuPermit.new.class -%>
<%= show_for @owner_user do |s| %>
  <%= s.attribute :username %>
  <%= s.attribute :email %>
  <!--%= s.attribute :password %-->
  <%= s.association :cms_roles, :collection_tag => :ol do |cms_role| %>
    <li><%= cms_role.name if cms_role %></li>
  <% end %>
  <%= s.association :cms_roles, :collection_tag => :ol do |cms_role| %>
    <%= cms_role.name %>
    <% cms_role.cms_role_permits.each do |cms_role_permit| %>
      <li><%= cms_role_permit.permit.name if cms_role_permit.permit %></li>
    <% end %>
  <% end %>
  <%= s.association :permits, :collection_tag => :ol do |permit| %>
    <li><%= permit if permit.present? %></li>
  <% end %>
  <%= s.attribute :sign_in_count %>
  <%= s.attribute :last_sign_in_at %>
<% end %>

<%= link_to t('.edit', :default => t("helpers.links.edit", :model => model_class.model_name.human)), edit_auth_assign_permit_path(@owner_user), :class => 'btn' %> |
<%= link_to t('.back', :default => t("helpers.links.back", :model => model_class.model_name.human)), auth_assign_permits_path, :class => 'btn' %> |
<%= link_to t('.destroy', :default => t("helpers.links.destroy", :model => model_class.model_name.human)), auth_assign_permit_path(@owner_user,:admin_group => params["admin_group"] ),
              :method => 'delete',
              :confirm => t('.confirm',
              :default => t("helpers.links.confirm", :default => 'Are you sure?')),
              :class => 'btn btn-danger' %>

add permit

#config/permits.yml
permit:
  create_profile: create_profile
  create_knowledge: create_knowledge
  create_news: create_news
  #create_category_base: create_category_base
  create_subject: create_subject
  create_attachment: create_attachment
  create_question: create_question
  
  ...
#cms_roles.yml
#encoding: utf-8
roles: ['admin','editoradmin','editor','operatoradmin','operator','guest']
#db/seeds.rb
##################default cms_roles
=begin
BBTangCMS::Config.cms_roles[:roles].each do |r|
  if r.present?
    CmsRole.find_or_create_by_name(r)
  end
end
=end
=begin
admin = CmsRole.find_by_name("admin")
editoradmin = CmsRole.find_by_name("editoradmin")
editor = CmsRole.find_by_name("editor")
operatoradmin = CmsRole.find_by_name("operatoradmin")
operator = CmsRole.find_by_name("operator")
UserRoles :Admin
user1 = User.find_by_email("[email protected]")
user1.cms_roles << admin
user2 = User.find_by_email("[email protected]")
user2.cms_roles << admin
=end
#################setting permits the first you should makesure you do it in cancan Ability
if BBTangCMS::Config.permits.has_key? :permit
  BBTangCMS::Config.permits[:permit].each do |kv|
    Permit.find_or_create_by_name(kv[0]) if kv.present?
  end
end
# encoding: utf-8
class ApplicationController < ActionController::Base
#check_authorization :unless => :do_not_check_authorization?
#check_authorization :unless => :devise_controller?
check_authorization :unless => :do_not_check_authorization?
rescue_from CanCan::AccessDenied do |exception|
if current_user
if current_user.has_cms_role? :guest
redirect_to root_url, :alert => exception.message
else
#render :file => "#{Rails.root}/public/403.html", :status => 403
sign_out current_user
redirect_to "http://bbtang.com"
end
end
end
def default_url_options(options = {})
options.merge! :host => "cms.bbtang.com" if Rails.env.production?
options.merge! :page => session[:old_page]# if session[:old_page].present?# and !(params[:page].eql? session[:old_page])
options
#if Rails.env.production?
# { :host => "cms.bbtang.com",
# #:locale => I18n.locale
# }
#else
# {}
#end
end
def bbtangcms_config
@@bbtangcms_config = BBTangCMS::Config.default
end
private
def do_not_check_authorization?
respond_to?(:devise_controller?) or skip_rails_kindeditor? or skip_messages?
#condition_two?
#respond_to?(:devise_controller?)# or respond_to?(:dashboard_controller?)
#debugger
end
def skip_rails_kindeditor?
true if params[:controller] == "kindeditor/assets"
end
def skip_messages?
true if params[:controller] == "messages"
end
def current_ability
# I am sure there is a slicker way to capture the controller namespace
controller_name_segments = params[:controller].split('/')
controller_name_segments.pop
controller_namespace = controller_name_segments.join('/')
Ability.new(current_user, controller_namespace)
end
end
#In summary:
# config/initializers/load_config.rb
#APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]
# application.rb
#if APP_CONFIG['perform_authentication']
# Do stuff
#end
require 'delegate'
module BBTangCMS
class Config < SimpleDelegator
def initialize(file_name)
super(symbolize_keys( YAML.load_file(file_name)[Rails.env] || YAML.load_file(file_name)))
end
def [](*path)
path.inject(__getobj__()) {|config, item|
config[item]
}
end
#def author_open_ids
# [self[:author, :open_id]].flatten.map {|uri| URI.parse(uri)}
#end
def self.default
BBTangCMS::Config.new(default_location)
end
def self.default_location
"#{Rails.root}/config/bbtangcms.yml"
end
def self.sina
BBTangCMS::Config.new(sina_location)
end
def self.sina_location
"#{Rails.root}/config/oauth/sina.yml"
end
def self.qq
BBTangCMS::Config.new(qq_location)
end
def self.qq_location
"#{Rails.root}/config/oauth/qq.yml"
end
def self.tag
BBTangCMS::Config.new(tag_location)
end
def self.tag_location
"#{Rails.root}/config/tag.yml"
end
def self.cms_roles
BBTangCMS::Config.new(cms_roles_location)
end
def self.cms_roles_location
"#{Rails.root}/config/cms_roles.yml"
end
def self.permits
BBTangCMS::Config.new(permits_location)
end
def self.permits_location
"#{Rails.root}/config/permits.yml"
end
private
def symbolize_keys(hash)
hash.inject({}) do |options, (key, value)|
options[(key.to_sym rescue key) || key] = value.is_a?(Hash) ? symbolize_keys(value) : value
options
end
end
end
end

schema

###schema
ActiveRecord::Schema.define(:version => 20121203030140) do
  create_table "assignments", :force => true do |t|
    t.integer  "user_id",     :null => false
    t.integer  "cms_role_id", :null => false
    t.datetime "created_at",  :null => false
    t.datetime "updated_at",  :null => false
  end

create_table "cms_roles", :force => true do |t|
    t.string   "name",       :null => false
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "cu_permits", :force => true do |t|
    t.integer  "user_id"
    t.integer  "permit_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end
  
  create_table "permits", :force => true do |t|
    t.string   "name"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end
end

migrate

#20120627111828_create_assignments.rb
class CreateAssignments < ActiveRecord::Migration
  def change
    create_table :assignments do |t|
      t.integer :user_id, :null => false
      t.integer :cms_role_id, :null => false

      t.timestamps
    end

    add_index :assignments, [:user_id, :cms_role_id]
  end

  def down
    #drop_table :user_roles
    drop_table :assignments
  end
end
#20120627113928_create_cms_roles.rb
class CreateCmsRoles < ActiveRecord::Migration
  def change
    create_table :cms_roles do |t|
      t.string :name, :null => false
      t.timestamps
    end
  end
end
#20120628084209_create_cr_permits.rb
class CreateCrPermits < ActiveRecord::Migration
  def change
    create_table :cr_permits do |t|
      t.integer :cms_role_id
      t.integer :permit_id
      t.string :type

      t.timestamps
    end
  end
end
#20120628084849_create_permits.rb
class CreatePermits < ActiveRecord::Migration
  def change
    create_table :permits do |t|
      t.string :name

      t.timestamps
    end
  end
end
#20120629113431_create_cu_permits.rb
class CreateCuPermits < ActiveRecord::Migration
  def change
    create_table :cu_permits do |t|
      t.integer :user_id
      t.integer :permit_id

      t.timestamps
    end
  end
end
#user.rb
# encoding: utf-8
class User < ActiveRecord::Base


  has_many :assignments, :dependent => :destroy, :uniq => true
  has_many :cms_roles, :through => :assignments

  has_many :cu_permits, :dependent => :destroy, :uniq => true
  has_many :permits, :through => :cu_permits # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :confirmable, :lockable, :recoverable,
         :rememberable, :registerable, :trackable, :timeoutable, :validatable,
         :token_authenticatable
         
  ###########method for cancan authorization################
  def has_cms_role?(cms_role_sym)
    cms_roles.any? { |r| r.name.underscore.to_sym == cms_role_sym }
  end
  
  def admin_group
    self.cms_roles.collect {|cms_role| cms_role if cms_role.admin? }.compact
  end

  def admin_group?
    tmp = false
    if self.cms_roles.present?
      self.cms_roles.each do |cms_role|
        if cms_role.name.to_s.include? "admin"
          tmp = true
        end
      end
    end
    tmp
  end

  def limit_admin_group
    self.cms_roles.collect {|cms_role| cms_role if cms_role.admin? and !cms_role.supper_admin? }.compact
  end

  def limit_admin_group?
    tmp = false
    if self.cms_roles.present?
      self.cms_roles.each do |cms_role|
        if cms_role.name.to_s.include? "admin" and not cms_role.supper_admin?
          tmp = true
        end
      end
    end
    tmp
  end

  def owner_users(name = nil)
    if self.admin_group? and name.present?
      owner_name = name.gsub("admin",'')
      User.joins(:cms_roles).where('cms_roles.name =?',owner_name)
    else
      []
    end
  end

  def supper_admin?
    tmp = false
    self.cms_roles.each do |cms_role|
      tmp = true if cms_role.to_s.eql? "admin"
    end
    tmp
  end

  def admin_assign_permits(cms_role = nil)
    admin_assign_permits = []
    if cms_role.present? and self.cms_roles.include? cms_role and cms_role.admin?
      cms_role.assign_permits.each do |assign_permit|
        admin_assign_permits.append assign_permit.permit if assign_permit.permit.present?
      end
      admin_assign_permits
    else
      admin_assign_permits
    end
  end

  def update_user_permit(new_cms_role_ids = [])

    new_cms_role_ids.collect!{|new_cms_role_id| new_cms_role_id.to_i if new_cms_role_id.present?}.compact!

    if self.cms_role_ids.sort != new_cms_role_ids.sort
      self.permits = []
    end
  end

  def is_cms_user?
    tmp = false
    if self.cms_roles.present?
      self.cms_roles.each do |cms_role|
        if cms_role.name.to_s.include? "guest" or CmsRole.all.include? cms_role
          tmp = true
        end
      end
    end
    return tmp
  end

  def cms_permits_all
    (permits.to_a.clone << cms_roles.collect{|cr| cr.cms_role_permits.collect{|crp| crp.permit}}).uniq.flatten
  end
  
  def find_cms_permit_by_name(name="")
    if self.present? and name.present?
      #find permit by name from user's permit cu_permits association
      permit = Permit.joins(:cu_permits).where("cu_permits.user_id= ? and permits.name = ?",self.id,name).limit(1).first
      #find permit by name from user's cms_role's cms_role_permits permit association
      if permit.nil?
        # this will find permit by name from user's all(cu_permits, cms_role's cms_role_permits, assign_permits) permit association
        #permit = Permit.joins(:users).where("users.id = 36 and permits.name = ?",self.id,name).limit(1)
        #因为 cms_role_permits 对应于 cms_role 是 一对多关系所以 cms_role 是单数,而反之却是多对一关系 CmsRole.joins(:cms_role_permit),同理 CmsRolePermit.joins(:cms_role)
        permit = Permit.joins(:cms_role_permits => {:cms_role=> :assignments}).where("assignments.user_id = ? and permits.name = ?",self.id,name).limit(1).first
      end

      permit
    end
  end
  
  def has_permit?(name = "")
    if name.present?
      find_cms_permit_by_name(name).present? ? true : false
    else
      false
    end
  end
  #########################################################
end
#assignment.rb
#assign role to user
class Assignment < ActiveRecord::Base
  belongs_to :user
  belongs_to :cms_role
  validates_uniqueness_of [:user_id, :cms_role_id]
end
#cms_role.rb
#define cms_role
class CmsRole < ActiveRecord::Base
  has_many :assignments
  has_many :users, :through => :assignments
  has_many :assign_permits, :dependent => :destroy, :uniq => true
  has_many :cms_role_permits, :dependent => :destroy, :uniq => true
  #has_many :permits, :through => :assign_permits
  before_save :set_limit_role

  validates :name, :presence => true, :uniqueness => true

  def set_assign_permits_list (assign_permit_list = [])
    if assign_permit_list.present? and assign_permit_list != [""]
      self.assign_permits.destroy_all
      assign_permit_list.each do |permit_id|
        self.assign_permits.create( permit_id: permit_id) if Permit.exists? permit_id
      end
    else
      self.assign_permits = []
    end
  end
  def set_cms_role_permits_list (cms_role_permits = [])

    if cms_role_permits.present? and cms_role_permits != [""]
      self.cms_role_permits.destroy_all
      cms_role_permits.each do |permit_id|
        self.cms_role_permits.create(permit_id: permit_id) if Permit.exists? permit_id
      end
    else
      self.cms_role_permits = []
    end
  end
  
  #limit user ["guest","editor","operator"]
  def set_limit_role
    if ["guest","editor","operator"].include? self.name
      self.assign_permits = []
    end
  end

  def admin?
    true if self.name.to_s.include? "admin"
  end


  def supper_admin?
    true if self.name.to_s == "admin"
  end

  def to_s
    self.name if self.name.present?
  end

end
#cu_permit.rb
#relationship table of user and permit
class CuPermit < ActiveRecord::Base
  belongs_to :user
  belongs_to :permit
  validates  :user_id, :permit_id, :presence => true
  validates_uniqueness_of [:user_id, :permit_id]
end
#cr_permit.rb
#relationship table of cms_role and permit
class CrPermit < ActiveRecord::Base
  belongs_to :cms_role
  belongs_to :permit
  validates :cms_role_id, :permit_id, :presence => true
  #这是单表继承的父类 唯一就放到 子类里面去做了
  #validates_uniqueness_of [:cms_role_id, :permit_id]
end
#cms_role_permit.rb
#relationship table of cms_role and (**exec** permit)
class CmsRolePermit < CrPermit
  validates_uniqueness_of [:cms_role_id, :permit_id]
end
#assign_permit.rb
#relationship table of cms_role and (can **assgin** permit)
class AssignPermit < CrPermit
  validates_uniqueness_of [:cms_role_id, :permit_id]
end
#permit.rb
class Permit < ActiveRecord::Base
  has_many :cu_permits
  has_many :cr_permits
  has_many :assign_permits
  has_many :cms_role_permits
  has_many :users, :through => :cu_permits
  validates :name, :presence => true, :uniqueness => true

  def to_s
    self.name if self.name.present?
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment