1

プロローグ

私はSqueelを採用しました–そしてすべてのステップを楽しんでいます!アーニーミラー、共有していただきありがとうございます!

私はruby1.9.2とSqueel1.0.2とRails3.2.5で開発しています

(質問を完全に再構成したことを告白します-読みやすさを向上させ、答えを得る可能性を高めることを望んでいます)<:)

使用事例

(スーパー)ユーザーがこのような承認と権限を割り当てることができるようにしたいと思います

  • user_groupは複数の権限を持つことができる必要があります
  • 承認は複数の権限を持つことができる必要があります
  • 権限は、データへのアクセス(操作)を制御できる必要があります
    • コントローラ経由(リクエストパス)
    • クラスのインスタンスで
    • 特定のインスタンスで

ACLシステムは怠惰である必要があります。つまり、役割/承認が与えられていない場合、ユーザーは明らかにACLにまったく関心がありません。

移行

ユースケースから役割と(多形の)役割のあるエンティティを特定したので、

普通ではない役割

create_table :roles do |t|
  t.references :ox
  t.string :name
  t.boolean :active, default: true
  t.timestamps
end

ともう少し説明的なRoleable

create_table :roleables do |t|
  t.references :ox
  t.references :role
  t.references :roleable, polymorphic: true
  t.string :authorization
  t.string :controller
  t.boolean :active, default: true
  t.timestamps
end

クラス

システムには、ActiveRecord:Baseから継承し、すべてのクラスから継承するジェネリッククラス(AbstractActionBase)があります(システム全体の属性とメソッドを1か所に追加できます)

つまり、部分的には、AbstractActionBaseは次のようになります。

class AbstractActionBase < ActiveRecord::Base
  self.abstract_class=true

  require 'tempfile'

  belongs_to :ox

  has_many :roleables, as: :roleable

  attr_accessible :ox_id

  validates_presence_of :ox_id

  #
  # all models inheriting from this will have versions
  has_paper_trail
  #
  #

  # 
  # Class method to providing for index SELECT's being married with roleables (permissions)
  # used from abstraction_actions_controller where build_collection calls this method 
  # the result 'should' be an ActiveRelation - used for the Kamanari 'result' call to readying pagination
  #
  def self.with_authorizations    

    # 
    # SELECT * FROM any_table at
    # left join (
    #     select r.roleable_id, r.roleable_type, group_concat( r.authorization )
    #   from roleables r
    #   where r.authorization is not null
    #   and r.roleable_id=at.id
    #   and r.roleable_type=at.base_class
    #   and r.role_id not in (1,2,3) <--- ID's are current_user.roles
    # ) rm on rm.roleable_id=at.id and rm.roleable_type=at.base_class
    #
    # which will provide for this:
    #
    # |.......| last column in table 'at' | roleable_id | roleable_type | authorizations |
    # |.......| some value                | 1           | 'UserGroup'   | 'insert,create'|
    # |.......| yet another value         | 92          | 'UserGroup'   | 'read'         |
    #
    #
    self.where{ active==true }
  end

  # compile a collection of records - regard search using Ransack
  def base.collection( params, resource_set )
    #
    # kaminari (and continous scrolling)
    #
    params[:page] ||= 1
    params[:per_page] ||= self.per_page
    params[:o] ||= self.resource_order_by
    distinct = params[:distinct].nil? ? false : params[:distinct].to_i.zero?
    resource_set = (resource_set.respond_to?( "result")) ? resource_set.result(:distinct => distinct) : resource_set
    (resource_set.respond_to?( "page")) ? resource_set.order(params[:o]).page( params[:page] ).per( params[:per_page] ) : resource_set.order(params[:o])
  end
end

Roleクラスの一部は次のようになります

class Role < AbstractActionBase

  has_many :roleables

  scope :active, where{ active.eq true }

  #
  # what does this role allow
  def permissions
    roleables.permissions.scoped
  end

  # 
  # to whom does this role allow
  def authorizations
    roleables.authorizations.scoped
  end

  # returns true if the roleables (permissions) authorizes the options
  # options are { controller: "", action: "", record: Instance, is_class: boolean }
  def authorizes?( options={} )
    coll = permissions
    coll = coll.on_action(options.delete(:action)) if options.keys.include? :action
    coll = coll.on_entity( options.delete(:record), options.delete(:is_class) || false ) if options.keys.include? :record
    coll = coll.on_controller(options.delete(:controller)) if options.keys.include? :controller
    (coll.count>0) === true
  end
end

Roleableクラスは次のようになります

class Roleable  < AbstractActionBase
  belongs_to :role
  belongs_to :roleable, polymorphic: true

  # roleables authorizes users through user_groups
  # (in which case the authorization is "-")
  # providing them permissions on controllers, actions and instances
  scope :authorizations, where{ authorization == nil }
  scope :permissions, where{ authorization != nil }

  # using Squeel, find roleables on a particular controller or any controller
  def self.on_controller(ctrl)
    where{ (controller==ctrl) | (controller==nil) }
  end

  # using Squeel, find roleables on a particular authorization or allowed 'all'
  def self.on_action(action)
    where{ (authorization=~ "%#{action}%") | (authorization=="all") }
  end

  # using Squeel, find roleables on a particular instance/record or class
  def self.on_entity(entity, is_class=false)
    if is_class
      where{ ((roleable_type==entity.base_class.to_s ) & ( roleable_id==nil)) | ((roleable_type==nil) & (roleable_id==nil)) }
    else
      where{ ((roleable_type==entity.class.to_s ) & ( roleable_id==entity.id)) | ((roleable_type==nil) & (roleable_id==nil)) }
    end
  end
end

論理

作成

これにより、承認(誰か/何かに役割を割り当てる)が可能になります。この場合、承認文字列はnilです。

user_group salesには 、Roleable.create({role:@sales、roleable:@user_group})を使用してロールsalesが割り当てられます。

同時に、私は許可を行うことができます-任意の役割の詳細を説明します-のように

役割salesには、OrderHeadテーブルとOrderDetailテーブルに対するインデックス作成編集、および削除の権限があります。

  • Roleable.create({role:@sales、authorization: "index、create、edit、delete"、roleable:@user_group、controller: "order_heads"})
  • Roleable.create({role:@sales、authorization: "index、create、edit、delete"、roleable:@user_group、controller: "order_details"})

これらの「詳細」は、次のようにエーテル的である可能性があります

Roleable.create({role:@sales、authorization: "index"})

ややリアル

Roleable.create({role:@sales、authorization: "index"、roleable_type:'OrderHead'})

または非常に表現された

Roleable.create({role:@sales、authorization: "index"、roleable:OrderHead.first})

選択

ほとんどすべてのコントローラーは、インデックス(およびその他のアクション)が定義されているAbstractActionsControllerから継承します。このように、そのコントローラーは、AttachedResources:Baseから自己継承します。

class AbstractActionsController < InheritedResources::Base # < ApplicationController

  append_view_path ViewTemplate::Resolver.instance

  respond_to :html, :xml, :json, :js, :pdf

  belongs_to :ox, :optional => true

  before_filter :authorize!
  before_filter :authenticate!
  before_filter :warn_unless_confirmed!
  before_filter :fix_money_params, :only => [:create,:update]

  # GET /collection - printers
  def index

    # session[:params] = params
    #
    # preparing for Ransack
    unless params[:q].nil?
      params[:q]= { :"#{params[:q_fields]}" => params[:q] }
    end

    super do |format|
      format.html 
      format.js { render layout: false }
      format.pdf{ render :pdf => generate_pdf(false) and return }
      format.xml { render layout: false }
      format.json do
        # field lookup request?
        unless params[:lookup].nil?
          render layout: false, :json => collection.map(&:select_mapping)
        else
          render json: collection.map { |p| view_context.grow_mustache_for_index(p, collection, (parent? ? collection : resource_class.order(:id)), @selected ) }
        end
      end
    end
  end


  # the collection method on inherited_resources 
  # gets overloaded with Ransack search and Kaminari pagination (on the model)
  def collection
    # @collection ||= build_collection
    # TODO - test whether caching the collection is possible
    build_collection
  end

  def build_collection
    unless params[:belongs].nil?
      # debugger
      parent = params[:belongs].constantize.find(params[:belongs_id])
      @selected = parent.nil? ? [] : parent.send( rewrite_association(params[:assoc],parent) )
      @search_resource = core_entity(params[:assoc].constantize)
      @search_resource = @search_resource.search(params[:q]) unless params[:q].nil?
    else
      @search_resource = rewrite_end_of_association_chain(resource_class)
      @search_resource = core_entity(@search_resource)
      @search_resource = @search_resource.search(params[:q]) unless params[:q].nil?
    end
    # authorize rows
    @search_resource = @search_resource.with_authorizations                 # left joins roleables coalescing a "authorization" field from roles ID's not owned by current_user through his user_groups
    @resources ||= resource_class.collection( params, @search_resource )
  end

end

チャレンジ

短い質問を提示するのはなんと長い話でしょう<:)

with_authorizationsActiveRelationを返すメソッドを作成するにはどうすればよいですか(できればSqueelを使用して)

4

2 に答える 2

1

ウォルト、

これを必要以上に複雑にしている可能性があります。この権利を読んでいる場合、サブクエリの主な目的は、結果で使用可能な権限の連結リストを取得することです。この場合、単にeager_load権限をロードし、連結を行うロールモデルのメソッドを介してそれらの名前を公開できます。これには、MySQL以外のDBと互換性があるという副次的な利点があります。

于 2012-07-09T13:58:53.587 に答える
0

私が言ったように-できればSqueelを使用して:)

(いわば馬の口から)参加はSqueel郡の協会のためのものであることが判明しました;)

じゃあ何をすればいいの?さて、 SQLからActiveRecordへの投げ縄を振って最後のツアーを行いました。誰かが素晴らしい質問をしました-そしてさらに大きな答えがありました!完全。

数回の短い熱の盲目の瞬間に、私は説明されたテクニックを使ってハッキングしました-そしてHeureka !!

以前は、可能な「回答者」を支援するためにパスティービンを追加しました。そのため、結果をパスティービンに追加しましたが、簡単に言うと次のようになります。

Model.select("something").joins("to your hearts contend")

乾杯、ワルサー

于 2012-07-12T15:37:37.183 に答える